package edu.kit.aifb.cumulus;
import static org.junit.Assert.assertEquals;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
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.impl.ContextStatementImpl;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.model.impl.ValueFactoryImpl;
import org.openrdf.query.QueryEvaluationException;
import org.openrdf.query.QueryResult;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFHandlerException;
import org.openrdf.rio.RDFWriter;
import org.openrdf.rio.Rio;
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;
/**
* Test data and utilities.
*
* @author Andreas Wagner
* @author Andrea Gazzarini
* @since 1.0
*/
public abstract class TestUtils {
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);
public 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" };
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.
* @param <T> the iterator element type.
* @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;
}
/**
* Builds a bnode.
*
* @param id the blank node identifier.
* @return a blank node.
*/
public static BNode buildBNode(final Object id) {
return VALUE_FACTORY.createBNode(String.valueOf(id));
}
/**
* 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 name the resource name.
* @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 {
final Value[] pattern = crdf instanceof TripleStore ? SELECT_ALL_TRIPLES_PATTERN : SELECT_ALL_QUADS_PATTERN;
crdf.removeData(pattern);
assertEquals("Store seems not empty after issuing a delete * command.", 0, numOfRes(crdf.query(pattern)));
}
/**
* 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.
* @param <T> the iterator element type.
* @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;
}
/**
* Returns how many triples are in the given query result..
*
* @param result the query result.
* @param <T> the query result element type.
* @return how many triples are in the given iterator.
* @throws QueryEvaluationException in case of failure while iterating the query result.
*/
public static <T> int numOfRes(final QueryResult<T> result) throws QueryEvaluationException {
int numOfTriples = 0;
while (result.hasNext()) {
result.next();
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();
}
/**
* Creates a list of random statements.
* @param random The pseudo random generator used for string generation.
* @param amount The amount of statements to generate.
* @return A list with random statements.
*/
public static List<Statement> randomStatements(final Random random, final int amount) {
List<Statement> list = new ArrayList<Statement>(amount);
for (int i = 0; i < amount; i++) {
list.add(new ContextStatementImpl(
new URIImpl("http://a.b/" + randomString(random, 32)),
new URIImpl("http://a.b/" + randomString(random, 32)),
new URIImpl("http://a.b/" + randomString(random, 32)),
new URIImpl("http://a.b/" + randomString(random, 32))));
}
return list;
}
/**
* Generates a random string.
*
* @return a random string.
*/
public static final String randomString() {
final long random = RANDOMIZER.nextLong() + 1;
return String.valueOf(random > 0 ? random : (random * -1));
}
/**
* Returns a random string constructed with the given {@code Random} object and the specified length.
* The string will contain characters matching [a-zA-Z0-9].
*
* @param random The pseudo random generator used for string generation.
* @param length The length of the string to return.
* @return A random string with the given length.
*/
public static String randomString(final Random random, final int length) {
StringBuilder str = new StringBuilder(length);
String allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
for (int i = 0; i < length; i++) {
str.append(allowedChars.charAt(random.nextInt(allowedChars.length())));
}
return str.toString();
}
/**
* Converts a statement iterator to an input stream with serialized RDF data.
*
* @param statements The statement iterator.
* @param format The RDF format to use for serialization.
* @return The serialized RDF data.
* @throws RDFHandlerException in case of operation failure.
*/
public static InputStream statementIteratorToRdfStream(final Iterator<Statement> statements, final RDFFormat format) throws RDFHandlerException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
RDFWriter rdfWriter = Rio.createWriter(format, stream);
rdfWriter.startRDF();
while (statements.hasNext()) {
rdfWriter.handleStatement(statements.next());
}
rdfWriter.endRDF();
return new ByteArrayInputStream(stream.toByteArray());
}
}