package edu.kit.aifb.cumulus; import static org.junit.Assert.assertEquals; import info.aduna.iteration.Iterations; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; import javax.xml.datatype.XMLGregorianCalendar; import org.openrdf.model.BNode; import org.openrdf.model.Literal; import org.openrdf.model.Statement; import org.openrdf.model.URI; import org.openrdf.model.Value; import org.openrdf.model.ValueFactory; import org.openrdf.model.datatypes.XMLDatatypeUtil; import org.openrdf.model.impl.ValueFactoryImpl; import org.openrdf.model.vocabulary.XMLSchema; import org.openrdf.query.Binding; import org.openrdf.query.BindingSet; import org.openrdf.query.QueryEvaluationException; import org.openrdf.query.QueryResult; import org.openrdf.query.TupleQueryResult; import edu.kit.aifb.cumulus.framework.datasource.DataAccessLayerFactory; import edu.kit.aifb.cumulus.framework.datasource.StorageLayout; import edu.kit.aifb.cumulus.store.CumulusStoreException; import edu.kit.aifb.cumulus.store.QuadStore; import edu.kit.aifb.cumulus.store.Store; import edu.kit.aifb.cumulus.store.TripleStore; import edu.kit.aifb.cumulus.util.Util; /** * Test data and utilities. * * @author Andreas Wagner * @author Andrea Gazzarini * @since 1.0 */ public abstract class WebTestUtils { public static class LineSeparator { // Windows: \r\n Unix: \n Mac: \r public static final String WIN = "\r\n", MAC = "\r", UNIX = "\n"; public static final String[] ALL = new String[] { WIN, MAC, UNIX }; } public static final DataAccessLayerFactory T_DATA_ACCESS_LAYER_FACTORY = DataAccessLayerFactory.getDefaultDataAccessLayerFactory(StorageLayout.TRIPLE); public static final DataAccessLayerFactory Q_DATA_ACCESS_LAYER_FACTORY = DataAccessLayerFactory.getDefaultDataAccessLayerFactory(StorageLayout.QUAD); static final ValueFactory VALUE_FACTORY = ValueFactoryImpl.getInstance(); public static final Random RANDOMIZER = new Random(System.currentTimeMillis()); public static final String[] EMPTY_STRINGS = { "", " ", "\n\r", "\t" }; private static final String TMP_FILE = "./target/testing/tmp.txt"; public static final String EXAMPLE_CONFIG_FILE = "/cumulus.yaml"; public static final Value[] SELECT_ALL_TRIPLES_PATTERN = { null, null, null }; public static final Value[] SELECT_ALL_QUADS_PATTERN = { null, null, null, null }; public static final String STORE_LISTEN_ADDRESS = "localhost:9161"; public static final String TRIPLE_STORE_KEYSPACE_NAME = "KeyspaceCumulusTriple"; public static final String QUAD_STORE_KEYSPACE_NAME = "KeyspaceCumulusQuad"; /** * Converts a given iterator in a list. * @param <T> * * @param iterator the iterator. * @return a list containing elements found in the iterator. */ public static <T> List<T> asList(final Iterator<T> iterator) { final List<T> result = new ArrayList<T>(); while (iterator.hasNext()) { result.add(iterator.next()); } return result; } /** * Copied from org.openrdf.query.QueryResultUtil */ private static boolean bindingSetsMatch(final BindingSet bs1, final BindingSet bs2) { if (bs1.size() != bs2.size()) { return false; } for (Binding binding1 : bs1) { Value value1 = binding1.getValue(); Value value2 = bs2.getValue(binding1.getName()); if ((value1 instanceof BNode) && (value2 instanceof BNode)) { // BNode mappedBNode = bNodeMapping.get(value1); // // if (mappedBNode != null) { // // bNode 'value1' was already mapped to some other bNode // if (!value2.equals(mappedBNode)) { // // 'value1' and 'value2' do not match // return false; // } // } else { // // 'value1' was not yet mapped, we need to check if 'value2' // // is a // // possible mapping candidate // if (bNodeMapping.containsValue(value2)) { // // 'value2' is already mapped to some other value. // return false; // } // } return value1.equals(value2); } else { // values are not (both) bNodes if ((value1 instanceof Literal) && (value2 instanceof Literal)) { // do literal value-based comparison for supported datatypes Literal leftLit = (Literal) value1; Literal rightLit = (Literal) value2; URI dt1 = leftLit.getDatatype(); URI dt2 = rightLit.getDatatype(); if ((dt1 != null) && (dt2 != null) && dt1.equals(dt2) && XMLDatatypeUtil.isValidValue(leftLit.getLabel(), dt1) && XMLDatatypeUtil.isValidValue(rightLit.getLabel(), dt2)) { Integer compareResult = null; if (dt1.equals(XMLSchema.DOUBLE)) { compareResult = Double.compare(leftLit.doubleValue(), rightLit.doubleValue()); } else if (dt1.equals(XMLSchema.FLOAT)) { compareResult = Float.compare(leftLit.floatValue(), rightLit.floatValue()); } else if (dt1.equals(XMLSchema.DECIMAL)) { compareResult = leftLit.decimalValue().compareTo(rightLit.decimalValue()); } else if (XMLDatatypeUtil.isIntegerDatatype(dt1)) { compareResult = leftLit.integerValue().compareTo(rightLit.integerValue()); } else if (dt1.equals(XMLSchema.BOOLEAN)) { Boolean leftBool = Boolean.valueOf(leftLit.booleanValue()); Boolean rightBool = Boolean.valueOf(rightLit.booleanValue()); compareResult = leftBool.compareTo(rightBool); } else if (XMLDatatypeUtil.isCalendarDatatype(dt1)) { XMLGregorianCalendar left = leftLit.calendarValue(); XMLGregorianCalendar right = rightLit.calendarValue(); compareResult = left.compare(right); } if (compareResult != null) { if (compareResult.intValue() != 0) { return false; } } else if (!value1.equals(value2)) { return false; } } else if (!value1.equals(value2)) { return false; } } else if (!value1.equals(value2)) { return false; } } } return true; } /** * Builds a literal with the given data. * * @param data the literal value. * @return a literal. */ public static Literal buildLiteral(final String data) { return VALUE_FACTORY.createLiteral(data); } /** * Builds a datatyped literal. * * @param data the literal value. * @param datatype the literal type. * @return a datatyped literal. */ public static Literal buildLiteral(final String data, final URI datatype) { return VALUE_FACTORY.createLiteral(data, datatype); } /** * Builds a new {@link URI} from a given string. * * @param value the uri as a string. * @return a new {@link URI} resource. */ public static URI buildResource(final String name) { return name.startsWith("http") ? VALUE_FACTORY.createURI(name) : VALUE_FACTORY.createURI("http://cumulus/" + name); } /** * Cleans up the given store. * * @param crdf could be a triple or a quad store. * @throws CumulusStoreException in case the cleanup fails. */ public static void clean(final Store crdf) throws CumulusStoreException { crdf.clear(); assertEquals("Store seems not empty after issuing a delete * command.", 0, numOfRes(crdf.query(crdf instanceof TripleStore ? SELECT_ALL_TRIPLES_PATTERN : SELECT_ALL_QUADS_PATTERN))); } public static String contentAsString(File file, String lineSepartor) throws IOException { BufferedReader br = new BufferedReader(new FileReader(file)); String line = null; StringBuilder sb = new StringBuilder(); while ((line = br.readLine()) != null) { sb.append(line.trim()); sb.append(System.getProperty("line.separator")); } br.close(); return sb.toString(); } public static String idToString(byte[] id) { StringBuilder sb = new StringBuilder(); for (byte b : id) { sb.append(String.format("%02X ", b)); } return sb.toString(); } public static Iterator<Statement> loadNTriplesFromFile(File file) throws FileNotFoundException { return Util.parseNXAsIterator(new FileInputStream(file)); } public static Iterator<Statement> loadNTriplesFromFile(String path) throws FileNotFoundException { return loadNTriplesFromFile(new File(path)); } /** * @see org.openrdf.query.QueryResultUtil */ public static boolean matchTupleQueryResults(TupleQueryResult res1, TupleQueryResult res2) throws QueryEvaluationException { List<BindingSet> queryResult1 = Iterations.asList(res1); List<BindingSet> queryResult2 = Iterations.asList(res2); if (queryResult1.size() != queryResult2.size()) { return false; } for (BindingSet bs1 : queryResult1) { boolean hit = false; for (BindingSet bs2 : queryResult2) { if (bindingSetsMatch(bs1, bs2)) { hit = true; break; } } if (!hit) { return false; } } return true; } /** * Returns a new instance of a quad store with default values. * * @return a new instance of a quad store with default values. */ public static final Store newQuadStore() { return new QuadStore(randomString()); } /** * Creates a new statement with the given data. * * @param localSubjectName the local subject name. * @param localPredicateName the local predicate name. * @param localObjectName the local object name. * @param localContextName the local context name. * @return a new statement. */ public static Statement newStatement( final String localSubjectName, final String localPredicateName, final String localObjectName, final String localContextName) { return VALUE_FACTORY.createStatement( buildResource(localSubjectName), buildResource(localPredicateName), buildResource(localObjectName), buildResource(localContextName)); } /** * Returns a new instance of a triple store with default values. * * @return a new instance of a triple store with default values. */ public static final Store newTripleStore() { return new TripleStore(randomString()); } /** * Returns how many triples are in the given iterator. * @param <T> * * @param nodes the iterator. * @return how many triples are in the given iterator. */ public static <T> int numOfRes(final Iterator<T> nodes) { int numOfTriples = 0; while (nodes.hasNext()) { nodes.next(); numOfTriples++; } return numOfTriples; } public static <T> int numOfRes(QueryResult<T> result) throws QueryEvaluationException { int numOfTriples = 0; while (result.hasNext()) { result.next(); numOfTriples++; } return numOfTriples; } public static int printIds(Iterator<byte[][]> ids, PrintStream stream) { if (!ids.hasNext()) { stream.println("nodes iterator empty"); return 0; } int numOfTriples = 0; while (ids.hasNext()) { byte[][] next_triple = ids.next(); if (next_triple.length == 4) { stream.println(idToString(next_triple[0]) + " " + idToString(next_triple[1]) + " " + idToString(next_triple[2]) + " " + idToString(next_triple[3]) + " . "); } else { stream.println(idToString(next_triple[0]) + " " + idToString(next_triple[1]) + " " + idToString(next_triple[2]) + " . "); } numOfTriples++; } return numOfTriples; } public static int printNQ(Iterator<Value[]> nodes, PrintStream stream) { if (!nodes.hasNext()) { stream.println("nodes iterator empty"); return 0; } int numOfTriples = 0; while (nodes.hasNext()) { Value[] next_triple = nodes.next(); stream.println(next_triple[0].toString() + " " + next_triple[1].toString() + " " + next_triple[2].toString() + " " + next_triple[3].toString() + " . "); numOfTriples++; } return numOfTriples; } public static int printNT(Iterator<Value[]> nodes, PrintStream stream) { if (!nodes.hasNext()) { stream.println("nodes iterator empty"); return 0; } int numOfTriples = 0; while (nodes.hasNext()) { Value[] next_triple = nodes.next(); stream.println(next_triple[0].toString() + " " + next_triple[1].toString() + " " + next_triple[2].toString() + " . "); numOfTriples++; } return numOfTriples; } /** * Generates a random int. * * @return a random int. */ public static final int randomInt() { return RANDOMIZER.nextInt(); } /** * Generates a random long. * * @return a random long. */ public static final long randomLong() { return RANDOMIZER.nextLong(); } /** * Generates a random string. * * @return a random string. */ public static final String randomString() { return String.valueOf(RANDOMIZER.nextLong()); } /** * Creates a tmp file under build directory. * * @return a reference to a temporary file. * @throws IOException * in case the file cannot be created. */ public static File tmpFile() throws IOException { final File tmp = new File(TMP_FILE); final File parentDirectory = tmp.getParentFile(); if (!parentDirectory.exists()) { parentDirectory.mkdirs(); } if (tmp.exists()) { tmp.delete(); } if (tmp.createNewFile()) { return tmp; } else { throw new IOException("File " + tmp.getAbsolutePath() + " cannot be created."); } } }