/* * This file is part of Gradoop. * * Gradoop is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Gradoop 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Gradoop. If not, see <http://www.gnu.org/licenses/>. */ package org.gradoop.common; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.flink.core.memory.DataInputView; import org.apache.flink.core.memory.DataInputViewStreamWrapper; import org.apache.flink.core.memory.DataOutputView; import org.apache.flink.core.memory.DataOutputViewStreamWrapper; import org.apache.flink.types.Value; import org.gradoop.common.config.GradoopConfig; import org.gradoop.common.model.api.entities.EPGMElement; import org.gradoop.common.model.api.entities.EPGMGraphElement; import org.gradoop.common.model.api.entities.EPGMIdentifiable; import org.gradoop.common.model.impl.comparators.EPGMIdentifiableComparator; import org.gradoop.common.model.impl.id.GradoopId; import org.gradoop.common.model.impl.pojo.Edge; import org.gradoop.common.model.impl.pojo.GraphHead; import org.gradoop.common.model.impl.pojo.Vertex; import org.gradoop.common.model.impl.properties.PropertyValue; import org.gradoop.common.util.AsciiGraphLoader; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import static org.junit.Assert.*; public class GradoopTestUtils { public static final String SOCIAL_NETWORK_GDL_FILE = "/data/gdl/social_network.gdl"; /** * Contains values of all supported property types */ public static Map<String, Object> SUPPORTED_PROPERTIES; public static final String KEY_0 = "key0"; public static final String KEY_1 = "key1"; public static final String KEY_2 = "key2"; public static final String KEY_3 = "key3"; public static final String KEY_4 = "key4"; public static final String KEY_5 = "key5"; public static final String KEY_6 = "key6"; public static final String KEY_7 = "key7"; public static final String KEY_8 = "key8"; public static final String KEY_9 = "key9"; public static final String KEY_a = "keya"; public static final String KEY_b = "keyb"; public static final String KEY_c = "keyc"; public static final String KEY_d = "keyd"; public static final Object NULL_VAL_0 = null; public static final boolean BOOL_VAL_1 = true; public static final int INT_VAL_2 = 23; public static final long LONG_VAL_3 = 23L; public static final float FLOAT_VAL_4 = 2.3f; public static final double DOUBLE_VAL_5 = 2.3; public static final String STRING_VAL_6 = "23"; public static final BigDecimal BIG_DECIMAL_VAL_7 = new BigDecimal(23); public static final GradoopId GRADOOP_ID_VAL_8 = GradoopId.get(); public static final Map<PropertyValue, PropertyValue> MAP_VAL_9 = new HashMap<>(); public static final List<PropertyValue> LIST_VAL_a = new ArrayList<>(); public static final LocalDate DATE_VAL_b = LocalDate.now(); public static final LocalTime TIME_VAL_c = LocalTime.now(); public static final LocalDateTime DATETIME_VAL_d = LocalDateTime.now(); private static Comparator<EPGMIdentifiable> ID_COMPARATOR = new EPGMIdentifiableComparator(); static { MAP_VAL_9.put(PropertyValue.create(KEY_0), PropertyValue.create(NULL_VAL_0)); MAP_VAL_9.put(PropertyValue.create(KEY_1), PropertyValue.create(BOOL_VAL_1)); MAP_VAL_9.put(PropertyValue.create(KEY_2), PropertyValue.create(INT_VAL_2)); MAP_VAL_9.put(PropertyValue.create(KEY_3), PropertyValue.create(LONG_VAL_3)); MAP_VAL_9.put(PropertyValue.create(KEY_4), PropertyValue.create(FLOAT_VAL_4)); MAP_VAL_9.put(PropertyValue.create(KEY_5), PropertyValue.create(DOUBLE_VAL_5)); MAP_VAL_9.put(PropertyValue.create(KEY_6), PropertyValue.create(STRING_VAL_6)); MAP_VAL_9.put(PropertyValue.create(KEY_7), PropertyValue.create(BIG_DECIMAL_VAL_7)); MAP_VAL_9.put(PropertyValue.create(KEY_8), PropertyValue.create(GRADOOP_ID_VAL_8)); MAP_VAL_9.put(PropertyValue.create(KEY_b), PropertyValue.create(DATE_VAL_b)); MAP_VAL_9.put(PropertyValue.create(KEY_c), PropertyValue.create(TIME_VAL_c)); MAP_VAL_9.put(PropertyValue.create(KEY_d), PropertyValue.create(DATETIME_VAL_d)); LIST_VAL_a.add(PropertyValue.create(NULL_VAL_0)); LIST_VAL_a.add(PropertyValue.create(BOOL_VAL_1)); LIST_VAL_a.add(PropertyValue.create(INT_VAL_2)); LIST_VAL_a.add(PropertyValue.create(LONG_VAL_3)); LIST_VAL_a.add(PropertyValue.create(FLOAT_VAL_4)); LIST_VAL_a.add(PropertyValue.create(DOUBLE_VAL_5)); LIST_VAL_a.add(PropertyValue.create(STRING_VAL_6)); LIST_VAL_a.add(PropertyValue.create(BIG_DECIMAL_VAL_7)); LIST_VAL_a.add(PropertyValue.create(GRADOOP_ID_VAL_8)); LIST_VAL_a.add(PropertyValue.create(DATE_VAL_b)); LIST_VAL_a.add(PropertyValue.create(TIME_VAL_c)); LIST_VAL_a.add(PropertyValue.create(DATETIME_VAL_d)); SUPPORTED_PROPERTIES = Maps.newTreeMap(); SUPPORTED_PROPERTIES.put(KEY_0, NULL_VAL_0); SUPPORTED_PROPERTIES.put(KEY_1, BOOL_VAL_1); SUPPORTED_PROPERTIES.put(KEY_2, INT_VAL_2); SUPPORTED_PROPERTIES.put(KEY_3, LONG_VAL_3); SUPPORTED_PROPERTIES.put(KEY_4, FLOAT_VAL_4); SUPPORTED_PROPERTIES.put(KEY_5, DOUBLE_VAL_5); SUPPORTED_PROPERTIES.put(KEY_6, STRING_VAL_6); SUPPORTED_PROPERTIES.put(KEY_7, BIG_DECIMAL_VAL_7); SUPPORTED_PROPERTIES.put(KEY_8, GRADOOP_ID_VAL_8); SUPPORTED_PROPERTIES.put(KEY_9, MAP_VAL_9); SUPPORTED_PROPERTIES.put(KEY_b, DATE_VAL_b); SUPPORTED_PROPERTIES.put(KEY_c, TIME_VAL_c); SUPPORTED_PROPERTIES.put(KEY_d, DATETIME_VAL_d); } /** * Creates a social network as a basis for tests. * <p/> * An image of the network can be found in * gradoop/dev-support/social-network.pdf * * @return graph store containing a simple social network for tests. */ public static AsciiGraphLoader<GraphHead, Vertex, Edge> getSocialNetworkLoader() throws IOException { GradoopConfig<GraphHead, Vertex, Edge> config = GradoopConfig.getDefaultConfig(); InputStream inputStream = GradoopTestUtils.class.getResourceAsStream(SOCIAL_NETWORK_GDL_FILE); return AsciiGraphLoader.fromStream(inputStream, config); } /** * Checks if the two collections contain the same identifiers. * * @param collection1 first collection * @param collection2 second collection */ public static void validateIdEquality( Collection<GradoopId> collection1, Collection<GradoopId> collection2) { List<GradoopId> list1 = Lists.newArrayList(collection1); List<GradoopId> list2 = Lists.newArrayList(collection2); Collections.sort(list1); Collections.sort(list2); Iterator<GradoopId> it1 = list1.iterator(); Iterator<GradoopId> it2 = list2.iterator(); while(it1.hasNext()) { assertTrue("id mismatch", it1.next().equals(it2.next())); } assertFalse("too many elements in first collection", it1.hasNext()); assertFalse("too many elements in second collection", it2.hasNext()); } /** * Checks if no identifier is contained in both lists. * * @param collection1 first collection * @param collection2 second collection */ public static void validateIdInequality( Collection<GradoopId> collection1, Collection<GradoopId> collection2) { for (GradoopId id1 : collection1) { for (GradoopId id2 : collection2) { assertFalse("id in both collections", id1.equals(id2)); } } } /** * Checks if two collections contain the same EPGM elements in terms of data * (i.e. label and properties). * * @param collection1 first collection * @param collection2 second collection */ public static void validateEPGMElementCollections( Collection<? extends EPGMElement> collection1, Collection<? extends EPGMElement> collection2) { assertNotNull("first collection was null", collection1); assertNotNull("second collection was null", collection1); List<? extends EPGMElement> list1 = Lists.newArrayList(collection1); List<? extends EPGMElement> list2 = Lists.newArrayList(collection2); Collections.sort(list1, ID_COMPARATOR); Collections.sort(list2, ID_COMPARATOR); Iterator<? extends EPGMElement> it1 = list1.iterator(); Iterator<? extends EPGMElement> it2 = list2.iterator(); while(it1.hasNext()) { validateEPGMElements( it1.next(), it2.next()); } assertFalse("too many elements in first collection", it1.hasNext()); assertFalse("too many elements in second collection", it2.hasNext()); } /** * Sorts the given collections by element id and checks pairwise if elements * are contained in the same graphs. * * @param collection1 first collection * @param collection2 second collection */ public static void validateEPGMGraphElementCollections( Collection<? extends EPGMGraphElement> collection1, Collection<? extends EPGMGraphElement> collection2) { assertNotNull("first collection was null", collection1); assertNotNull("second collection was null", collection1); List<? extends EPGMGraphElement> list1 = Lists.newArrayList(collection1); List<? extends EPGMGraphElement> list2 = Lists.newArrayList(collection2); Collections.sort(list1, ID_COMPARATOR); Collections.sort(list2, ID_COMPARATOR); Iterator<? extends EPGMGraphElement> it1 = list1.iterator(); Iterator<? extends EPGMGraphElement> it2 = list2.iterator(); while(it1.hasNext()) { validateEPGMGraphElements(it1.next(), it2.next()); } assertFalse("too many elements in first collection", it1.hasNext()); assertFalse("too many elements in second collection", it2.hasNext()); } /** * Checks if two given EPGM elements are equal by considering their label and * properties. * * @param element1 first element * @param element2 second element */ public static void validateEPGMElements(EPGMElement element1, EPGMElement element2) { assertNotNull("first element was null", element1); assertNotNull("second element was null", element2); assertEquals("id mismatch", element1.getId(), element2.getId()); assertEquals("label mismatch", element1.getLabel(), element2.getLabel()); if (element1.getPropertyCount() == 0) { assertEquals("property count mismatch", element1.getPropertyCount(), element2.getPropertyCount()); } else { List<String> keys1 = Lists.newArrayList(element1.getPropertyKeys()); Collections.sort(keys1); List<String> keys2 = Lists.newArrayList(element2.getPropertyKeys()); Collections.sort(keys2); Iterator<String> it1 = keys1.iterator(); Iterator<String> it2 = keys2.iterator(); while (it1.hasNext() && it2.hasNext()) { String key1 = it1.next(); String key2 = it2.next(); assertEquals("property key mismatch", key1, key2); assertEquals("property value mismatch", element1.getPropertyValue(key1), element2.getPropertyValue(key2)); } assertFalse("too many properties in first element", it1.hasNext()); assertFalse("too many properties in second element", it2.hasNext()); } } /** * Checks if two given EPGM graph elements are equal by considering the * graphs they are contained in. * * @param element1 first element * @param element2 second element */ public static void validateEPGMGraphElements( EPGMGraphElement element1, EPGMGraphElement element2) { assertNotNull("first element was null", element1); assertNotNull("second element was null", element2); assertTrue( String.format("graph containment mismatch. expected: %s actual: %s", element1.getGraphIds(), element2.getGraphIds()), element1.getGraphIds().equals(element2.getGraphIds()) ); } public static <T extends Value> T writeAndReadFields(Class<T> clazz, T in) throws IOException { // write to byte[] ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); DataOutputView outputView = new DataOutputViewStreamWrapper(outputStream); in.write(outputView); outputStream.flush(); T out; try { out = clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); throw new IOException("Cannot initialize the class: " + clazz); } // read from byte[] ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); DataInputView inputView = new DataInputViewStreamWrapper(inputStream); out.read(inputView); return out; } public static <T extends Value> T writeAndReadValue(Class<T> clazz, T in) throws Exception { // write to byte[] java.io.ByteArrayOutputStream outStream = new java.io.ByteArrayOutputStream(); DataOutputView dataOutputView = new DataOutputViewStreamWrapper(outStream); in.write(dataOutputView); T out; try { out = clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); throw new IOException("Cannot initialize the class: " + clazz); } // read from byte[] ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); DataInputView dataInputView = new DataInputViewStreamWrapper(inStream); out.read(dataInputView); return out; } /** * Uses reflection to call a private method with no arguments. * * @param clazz class which has the method * @param object instance of the class * @param methodName method name * @param <T1> return type of method * @param <T2> type of the calling class * @return method result * @throws Exception in case anything goes wrong */ @SuppressWarnings("unchecked") public static <T1, T2> T1 call(Class<T2> clazz, T2 object, String methodName) throws Exception { return call(clazz, object, methodName, null, null); } /** * Uses reflection to call a private method with arguments. * * @param clazz class which has the method * @param object instance of the class * @param methodName method name * @param args method arguments * @param <T1> return type of method * @param <T2> type of the calling class * @return method result * @throws Exception in case anything goes wrong */ @SuppressWarnings("unchecked") public static <T1, T2> T1 call(Class<T2> clazz, T2 object, String methodName, Class<?>[] parameterTypes, Object[] args) throws Exception { Method m = parameterTypes != null ? clazz.getDeclaredMethod(methodName, parameterTypes) : clazz.getDeclaredMethod(methodName); m.setAccessible(true); return (T1) (args != null ? m.invoke(object, args) : m.invoke(object)); } }