http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/geo/GeoIndexerTest.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/geo/GeoIndexerTest.java b/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/geo/GeoIndexerTest.java new file mode 100644 index 0000000..5e18696 --- /dev/null +++ b/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/geo/GeoIndexerTest.java @@ -0,0 +1,369 @@ +package mvm.rya.indexing.accumulo.geo; + +/* + * #%L + * mvm.rya.indexing.accumulo + * %% + * Copyright (C) 2014 Rya + * %% + * 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. + * #L% + */ + +import static mvm.rya.api.resolver.RdfToRyaConversions.convertStatement; +import info.aduna.iteration.CloseableIteration; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import mvm.rya.indexing.StatementContraints; +import mvm.rya.indexing.accumulo.ConfigUtils; + +import org.apache.accumulo.core.client.admin.TableOperations; +import org.apache.hadoop.conf.Configuration; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.openrdf.model.Resource; +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.StatementImpl; +import org.openrdf.model.impl.ValueFactoryImpl; + +import com.google.common.collect.Sets; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LinearRing; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.PrecisionModel; +import com.vividsolutions.jts.geom.impl.PackedCoordinateSequence; + +public class GeoIndexerTest { + + private static final StatementContraints EMPTY_CONSTRAINTS = new StatementContraints(); + + Configuration conf; + GeometryFactory gf = new GeometryFactory(new PrecisionModel(), 4326); + + @Before + public void before() throws Exception { + System.out.println(UUID.randomUUID().toString()); + String tableName = "triplestore_geospacial"; + conf = new Configuration(); + conf.setBoolean(ConfigUtils.USE_MOCK_INSTANCE, true); + conf.set(ConfigUtils.CLOUDBASE_USER, "USERNAME"); + conf.set(ConfigUtils.CLOUDBASE_PASSWORD, "PASS"); + conf.set(ConfigUtils.GEO_TABLENAME, tableName); + conf.set(ConfigUtils.CLOUDBASE_AUTHS, "U"); + + TableOperations tops = ConfigUtils.getConnector(conf).tableOperations(); + // get all of the table names with the prefix + Set<String> toDel = Sets.newHashSet(); + for (String t : tops.list()){ + if (t.startsWith(tableName)){ + toDel.add(t); + } + } + for (String t : toDel) { + tops.delete(t); + } + } + + @Test + public void testRestrictPredicatesSearch() throws Exception { + conf.setStrings(ConfigUtils.GEO_PREDICATES_LIST, "pred:1,pred:2"); + GeoMesaGeoIndexer f = new GeoMesaGeoIndexer(); + f.setConf(conf); + + ValueFactory vf = new ValueFactoryImpl(); + + Point point = gf.createPoint(new Coordinate(10, 10)); + Value pointValue = vf.createLiteral("Point(10 10)", GeoConstants.XMLSCHEMA_OGC_WKT); + URI invalidPredicate = GeoConstants.GEO_AS_WKT; + + // These should not be stored because they are not in the predicate list + f.storeStatement(convertStatement(new StatementImpl(vf.createURI("foo:subj1"), invalidPredicate, pointValue))); + f.storeStatement(convertStatement(new StatementImpl(vf.createURI("foo:subj2"), invalidPredicate, pointValue))); + + URI pred1 = vf.createURI("pred:1"); + URI pred2 = vf.createURI("pred:2"); + + // These should be stored because they are in the predicate list + Statement s3 = new StatementImpl(vf.createURI("foo:subj3"), pred1, pointValue); + Statement s4 = new StatementImpl(vf.createURI("foo:subj4"), pred2, pointValue); + f.storeStatement(convertStatement(s3)); + f.storeStatement(convertStatement(s4)); + + // This should not be stored because the object is not valid wkt + f.storeStatement(convertStatement(new StatementImpl(vf.createURI("foo:subj5"), pred1, vf.createLiteral("soint(10 10)")))); + + // This should not be stored because the object is not a literal + f.storeStatement(convertStatement(new StatementImpl(vf.createURI("foo:subj6"), pred1, vf.createURI("p:Point(10 10)")))); + + f.flush(); + + Set<Statement> actual = getSet(f.queryEquals(point, EMPTY_CONSTRAINTS)); + Assert.assertEquals(2, actual.size()); + Assert.assertTrue(actual.contains(s3)); + Assert.assertTrue(actual.contains(s4)); + + f.close(); + } + + private static <X> Set<X> getSet(CloseableIteration<X, ?> iter) throws Exception { + Set<X> set = new HashSet<X>(); + while (iter.hasNext()) { + set.add(iter.next()); + } + return set; + } + + @Test + public void testPrimeMeridianSearch() throws Exception { + + GeoMesaGeoIndexer f = new GeoMesaGeoIndexer(); + f.setConf(conf); + + ValueFactory vf = new ValueFactoryImpl(); + Resource subject = vf.createURI("foo:subj"); + URI predicate = GeoConstants.GEO_AS_WKT; + Value object = vf.createLiteral("Point(0 0)", GeoConstants.XMLSCHEMA_OGC_WKT); + Resource context = vf.createURI("foo:context"); + + Statement statement = new ContextStatementImpl(subject, predicate, object, context); + f.storeStatement(convertStatement(statement)); + f.flush(); + + double[] ONE = { 1, 1, -1, 1, -1, -1, 1, -1, 1, 1 }; + double[] TWO = { 2, 2, -2, 2, -2, -2, 2, -2, 2, 2 }; + double[] THREE = { 3, 3, -3, 3, -3, -3, 3, -3, 3, 3 }; + + LinearRing r1 = gf.createLinearRing(new PackedCoordinateSequence.Double(ONE, 2)); + LinearRing r2 = gf.createLinearRing(new PackedCoordinateSequence.Double(TWO, 2)); + LinearRing r3 = gf.createLinearRing(new PackedCoordinateSequence.Double(THREE, 2)); + + Polygon p1 = gf.createPolygon(r1, new LinearRing[] {}); + Polygon p2 = gf.createPolygon(r2, new LinearRing[] {}); + Polygon p3 = gf.createPolygon(r3, new LinearRing[] {}); + + Assert.assertEquals(Sets.newHashSet(statement), getSet(f.queryWithin(p1, EMPTY_CONSTRAINTS))); + Assert.assertEquals(Sets.newHashSet(statement), getSet(f.queryWithin(p2, EMPTY_CONSTRAINTS))); + Assert.assertEquals(Sets.newHashSet(statement), getSet(f.queryWithin(p3, EMPTY_CONSTRAINTS))); + + // Test a ring with a hole in it + Polygon p3m2 = gf.createPolygon(r3, new LinearRing[] { r2 }); + Assert.assertEquals(Sets.newHashSet(), getSet(f.queryWithin(p3m2, EMPTY_CONSTRAINTS))); + + // test a ring outside the point + double[] OUT = { 3, 3, 1, 3, 1, 1, 3, 1, 3, 3 }; + LinearRing rOut = gf.createLinearRing(new PackedCoordinateSequence.Double(OUT, 2)); + Polygon pOut = gf.createPolygon(rOut, new LinearRing[] {}); + Assert.assertEquals(Sets.newHashSet(), getSet(f.queryWithin(pOut, EMPTY_CONSTRAINTS))); + + f.close(); + } + + @Test + public void testDcSearch() throws Exception { + // test a ring around dc + GeoMesaGeoIndexer f = new GeoMesaGeoIndexer(); + f.setConf(conf); + + ValueFactory vf = new ValueFactoryImpl(); + Resource subject = vf.createURI("foo:subj"); + URI predicate = GeoConstants.GEO_AS_WKT; + Value object = vf.createLiteral("Point(-77.03524 38.889468)", GeoConstants.XMLSCHEMA_OGC_WKT); + Resource context = vf.createURI("foo:context"); + + Statement statement = new ContextStatementImpl(subject, predicate, object, context); + f.storeStatement(convertStatement(statement)); + f.flush(); + + double[] IN = { -78, 39, -77, 39, -77, 38, -78, 38, -78, 39 }; + LinearRing r1 = gf.createLinearRing(new PackedCoordinateSequence.Double(IN, 2)); + Polygon p1 = gf.createPolygon(r1, new LinearRing[] {}); + Assert.assertEquals(Sets.newHashSet(statement), getSet(f.queryWithin(p1, EMPTY_CONSTRAINTS))); + + // test a ring outside the point + double[] OUT = { -77, 39, -76, 39, -76, 38, -77, 38, -77, 39 }; + LinearRing rOut = gf.createLinearRing(new PackedCoordinateSequence.Double(OUT, 2)); + Polygon pOut = gf.createPolygon(rOut, new LinearRing[] {}); + Assert.assertEquals(Sets.newHashSet(), getSet(f.queryWithin(pOut, EMPTY_CONSTRAINTS))); + + f.close(); + } + + @Test + public void testDcSearchWithContext() throws Exception { + // test a ring around dc + GeoMesaGeoIndexer f = new GeoMesaGeoIndexer(); + f.setConf(conf); + + ValueFactory vf = new ValueFactoryImpl(); + Resource subject = vf.createURI("foo:subj"); + URI predicate = GeoConstants.GEO_AS_WKT; + Value object = vf.createLiteral("Point(-77.03524 38.889468)", GeoConstants.XMLSCHEMA_OGC_WKT); + Resource context = vf.createURI("foo:context"); + + Statement statement = new ContextStatementImpl(subject, predicate, object, context); + f.storeStatement(convertStatement(statement)); + f.flush(); + + double[] IN = { -78, 39, -77, 39, -77, 38, -78, 38, -78, 39 }; + LinearRing r1 = gf.createLinearRing(new PackedCoordinateSequence.Double(IN, 2)); + Polygon p1 = gf.createPolygon(r1, new LinearRing[] {}); + + // query with correct context + Assert.assertEquals(Sets.newHashSet(statement), getSet(f.queryWithin(p1, new StatementContraints().setContext(context)))); + + // query with wrong context + Assert.assertEquals(Sets.newHashSet(), + getSet(f.queryWithin(p1, new StatementContraints().setContext(vf.createURI("foo:context2"))))); + + f.close(); + } + + @Test + public void testDcSearchWithSubject() throws Exception { + // test a ring around dc + GeoMesaGeoIndexer f = new GeoMesaGeoIndexer(); + f.setConf(conf); + + ValueFactory vf = new ValueFactoryImpl(); + Resource subject = vf.createURI("foo:subj"); + URI predicate = GeoConstants.GEO_AS_WKT; + Value object = vf.createLiteral("Point(-77.03524 38.889468)", GeoConstants.XMLSCHEMA_OGC_WKT); + Resource context = vf.createURI("foo:context"); + + Statement statement = new ContextStatementImpl(subject, predicate, object, context); + f.storeStatement(convertStatement(statement)); + f.flush(); + + double[] IN = { -78, 39, -77, 39, -77, 38, -78, 38, -78, 39 }; + LinearRing r1 = gf.createLinearRing(new PackedCoordinateSequence.Double(IN, 2)); + Polygon p1 = gf.createPolygon(r1, new LinearRing[] {}); + + // query with correct subject + Assert.assertEquals(Sets.newHashSet(statement), getSet(f.queryWithin(p1, new StatementContraints().setSubject(subject)))); + + // query with wrong subject + Assert.assertEquals(Sets.newHashSet(), getSet(f.queryWithin(p1, new StatementContraints().setSubject(vf.createURI("foo:subj2"))))); + + f.close(); + } + + @Test + public void testDcSearchWithSubjectAndContext() throws Exception { + // test a ring around dc + GeoMesaGeoIndexer f = new GeoMesaGeoIndexer(); + f.setConf(conf); + + ValueFactory vf = new ValueFactoryImpl(); + Resource subject = vf.createURI("foo:subj"); + URI predicate = GeoConstants.GEO_AS_WKT; + Value object = vf.createLiteral("Point(-77.03524 38.889468)", GeoConstants.XMLSCHEMA_OGC_WKT); + Resource context = vf.createURI("foo:context"); + + Statement statement = new ContextStatementImpl(subject, predicate, object, context); + f.storeStatement(convertStatement(statement)); + f.flush(); + + double[] IN = { -78, 39, -77, 39, -77, 38, -78, 38, -78, 39 }; + LinearRing r1 = gf.createLinearRing(new PackedCoordinateSequence.Double(IN, 2)); + Polygon p1 = gf.createPolygon(r1, new LinearRing[] {}); + + // query with correct context subject + Assert.assertEquals(Sets.newHashSet(statement), + getSet(f.queryWithin(p1, new StatementContraints().setContext(context).setSubject(subject)))); + + // query with wrong context + Assert.assertEquals(Sets.newHashSet(), + getSet(f.queryWithin(p1, new StatementContraints().setContext(vf.createURI("foo:context2"))))); + + // query with wrong subject + Assert.assertEquals(Sets.newHashSet(), getSet(f.queryWithin(p1, new StatementContraints().setSubject(vf.createURI("foo:subj2"))))); + + f.close(); + } + + @Test + public void testDcSearchWithPredicate() throws Exception { + // test a ring around dc + GeoMesaGeoIndexer f = new GeoMesaGeoIndexer(); + f.setConf(conf); + + ValueFactory vf = new ValueFactoryImpl(); + Resource subject = vf.createURI("foo:subj"); + URI predicate = GeoConstants.GEO_AS_WKT; + Value object = vf.createLiteral("Point(-77.03524 38.889468)", GeoConstants.XMLSCHEMA_OGC_WKT); + Resource context = vf.createURI("foo:context"); + + Statement statement = new ContextStatementImpl(subject, predicate, object, context); + f.storeStatement(convertStatement(statement)); + f.flush(); + + double[] IN = { -78, 39, -77, 39, -77, 38, -78, 38, -78, 39 }; + LinearRing r1 = gf.createLinearRing(new PackedCoordinateSequence.Double(IN, 2)); + Polygon p1 = gf.createPolygon(r1, new LinearRing[] {}); + + // query with correct Predicate + Assert.assertEquals(Sets.newHashSet(statement), + getSet(f.queryWithin(p1, new StatementContraints().setPredicates(Collections.singleton(predicate))))); + + // query with wrong predicate + Assert.assertEquals(Sets.newHashSet(), + getSet(f.queryWithin(p1, new StatementContraints().setPredicates(Collections.singleton(vf.createURI("other:pred")))))); + + f.close(); + } + + // @Test + public void testAntiMeridianSearch() throws Exception { + // verify that a search works if the bounding box crosses the anti meridian + GeoMesaGeoIndexer f = new GeoMesaGeoIndexer(); + f.setConf(conf); + + ValueFactory vf = new ValueFactoryImpl(); + Resource context = vf.createURI("foo:context"); + + Resource subjectEast = vf.createURI("foo:subj:east"); + URI predicateEast = GeoConstants.GEO_AS_WKT; + Value objectEast = vf.createLiteral("Point(179 0)", GeoConstants.XMLSCHEMA_OGC_WKT); + Statement statementEast = new ContextStatementImpl(subjectEast, predicateEast, objectEast, context); + f.storeStatement(convertStatement(statementEast)); + + Resource subjectWest = vf.createURI("foo:subj:west"); + URI predicateWest = GeoConstants.GEO_AS_WKT; + Value objectWest = vf.createLiteral("Point(-179 0)", GeoConstants.XMLSCHEMA_OGC_WKT); + Statement statementWest = new ContextStatementImpl(subjectWest, predicateWest, objectWest, context); + f.storeStatement(convertStatement(statementWest)); + + f.flush(); + + double[] ONE = { 178.1, 1, -178, 1, -178, -1, 178.1, -1, 178.1, 1 }; + + LinearRing r1 = gf.createLinearRing(new PackedCoordinateSequence.Double(ONE, 2)); + + Polygon p1 = gf.createPolygon(r1, new LinearRing[] {}); + + Assert.assertEquals(Sets.newHashSet(statementEast, statementWest), getSet(f.queryWithin(p1, EMPTY_CONSTRAINTS))); + + f.close(); + } +}
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/temporal/AccumuloTemporalIndexerTest.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/temporal/AccumuloTemporalIndexerTest.java b/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/temporal/AccumuloTemporalIndexerTest.java new file mode 100644 index 0000000..c0ba19b --- /dev/null +++ b/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/temporal/AccumuloTemporalIndexerTest.java @@ -0,0 +1,1020 @@ +/** + * + */ +package mvm.rya.indexing.accumulo.temporal; + +import static mvm.rya.api.resolver.RdfToRyaConversions.convertStatement; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import info.aduna.iteration.CloseableIteration; + +import java.io.IOException; +import java.io.PrintStream; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; + +import junit.framework.Assert; +import mvm.rya.api.domain.RyaStatement; +import mvm.rya.indexing.StatementContraints; +import mvm.rya.indexing.TemporalInstant; +import mvm.rya.indexing.TemporalInterval; +import mvm.rya.indexing.accumulo.ConfigUtils; +import mvm.rya.indexing.accumulo.StatementSerializer; + +import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.client.AccumuloException; +import org.apache.accumulo.core.client.AccumuloSecurityException; +import org.apache.accumulo.core.client.Scanner; +import org.apache.accumulo.core.client.TableExistsException; +import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.accumulo.core.client.admin.TableOperations; +import org.apache.accumulo.core.data.Key; +import org.apache.accumulo.core.data.Value; +import org.apache.commons.codec.binary.StringUtils; +import org.apache.commons.io.output.NullOutputStream; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.io.Text; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openrdf.model.Statement; +import org.openrdf.model.URI; +import org.openrdf.model.ValueFactory; +import org.openrdf.model.impl.StatementImpl; +import org.openrdf.model.impl.ValueFactoryImpl; +import org.openrdf.model.vocabulary.RDFS; +import org.openrdf.query.QueryEvaluationException; + +import com.beust.jcommander.internal.Lists; + +/** + * JUnit tests for TemporalIndexer and it's implementation AccumuloTemporalIndexer + * + * If you enjoy this test, please read RyaTemporalIndexerTest and YagoKBTest, which contain + * many example SPARQL queries and updates and attempts to test independently of Accumulo: + * + * extras/indexingSail/src/test/java/mvm/rya/indexing/accumulo/RyaTemporalIndexerTest.java + * {@link mvm.rya.indexing.accumulo.RyaTemporalIndexerTest} + * {@link mvm.rya.indexing.accumulo.YagoKBTest.java} + * + * Remember, this class in instantiated fresh for each @test method. + * so fields are reset, unless they are static. + * + * These are covered: + * Instance {before, equals, after} given Instance + * Instance {before, after, inside} given Interval + * Instance {hasBeginning, hasEnd} given Interval + * And a few more. + * + */ +public final class AccumuloTemporalIndexerTest { + // Configuration properties, this is reset per test in setup. + Configuration conf; + // temporal indexer to test, this is created for each test method by setup. + AccumuloTemporalIndexer tIndexer; + + private static final String URI_PROPERTY_EVENT_TIME = "Property:event:time"; + private static final String URI_PROPERTY_CIRCA = "Property:circa"; + private static final String URI_PROPERTY_AT_TIME = "Property:atTime"; + private static final String STAT_COUNT = "count"; + private static final String STAT_KEYHASH = "keyhash"; + private static final String STAT_VALUEHASH = "valuehash"; + private static final String TEST_TEMPORAL_INDEX_TABLE_NAME = "testTemporalIndex"; + private static final StatementContraints EMPTY_CONSTRAINTS = new StatementContraints(); + + // Recreate table name for each test instance in this JVM. + String uniquePerTestTemporalIndexTableName = TEST_TEMPORAL_INDEX_TABLE_NAME + String.format("%05d", nextTableSuffixAtomic.getAndIncrement()); + // start at 0, for uniqueness between jvm's consider AtomicLong(new Random().nextLong()) + private static final AtomicLong nextTableSuffixAtomic = new AtomicLong(); + + // Assign this in setUpBeforeClass, store them in each test. + // setup() deletes table before each test. + static final Statement spo_B00_E01; + static final Statement spo_B03_E20; + static final Statement spo_B02_E29; + static final Statement spo_B02_E30; + static final Statement spo_B02_E40; + static final Statement spo_B02_E31; + static final Statement spo_B29_E30; + static final Statement spo_B30_E32; + + // Instants: + static final Statement spo_B02; + static final int SERIES_OF_SECONDS = 41; + static final Statement seriesSpo[] = new Statement[SERIES_OF_SECONDS]; + + // These are shared for several tests. Only the seconds are different. + // tvB03_E20 read as: interval Begins 3 seconds, ends at 20 seconds + static final TemporalInterval tvB00_E01 = new TemporalInterval(// + makeInstant(00), // + makeInstant(01)); + static final TemporalInterval tvB29_E30= new TemporalInterval(// + makeInstant(29), // + makeInstant(30)); + static final TemporalInterval tvB30_E32= new TemporalInterval(// + makeInstant(30), // + makeInstant(32)); + static final TemporalInterval tvB03_E20 = new TemporalInterval(// + makeInstant(03), // + makeInstant(20)); + // 30 seconds, Begins earlier, ends later + static final TemporalInterval tvB02_E30= new TemporalInterval(// + makeInstant(02), // + makeInstant(30)); + // use for interval after + static final TemporalInterval tvB02_E29= new TemporalInterval(// + makeInstant(02), // + makeInstant(29)); + // same as above, but ends in the middle + static final TemporalInterval tvB02_E31 = new TemporalInterval(// + makeInstant(02), // + makeInstant(31)); + // same as above, but ends even later + static final TemporalInterval tvB02_E40 = new TemporalInterval(// + makeInstant(02), // + makeInstant(40)); + // instant, match beginnings of several above, before tiB03_E20 + static final TemporalInstant tsB02 = makeInstant(02); + // instant, after all above + static final TemporalInstant tsB04 = makeInstant(04); + + // Create a series of instants about times 0 - 40 seconds + static final TemporalInstant seriesTs[]; + static { + seriesTs = new TemporalInstant[SERIES_OF_SECONDS]; + for (int i = 0; i <= 40; i++) + seriesTs[i] = makeInstant(i); + }; + + /** + * Make an uniform instant with given seconds. + */ + static TemporalInstant makeInstant(int secondsMakeMeUnique) { + return new TemporalInstantRfc3339(2015, 12, 30, 12, 00, secondsMakeMeUnique); + } + + static { + // Setup the statements only once. Each test will store some of these in there own index table. + ValueFactory vf = new ValueFactoryImpl(); + URI pred1_atTime = vf.createURI(URI_PROPERTY_AT_TIME); + // tiB03_E20 read as: time interval that Begins 3 seconds, ends at 20 seconds, + // Each time element the same, except seconds. year, month, .... minute are the same for each statement below. + spo_B00_E01 = new StatementImpl(vf.createURI("foo:event0"), pred1_atTime, vf.createLiteral(tvB00_E01.toString())); + spo_B02_E29 = new StatementImpl(vf.createURI("foo:event2"), pred1_atTime, vf.createLiteral(tvB02_E29.toString())); + spo_B02_E30 = new StatementImpl(vf.createURI("foo:event2"), pred1_atTime, vf.createLiteral(tvB02_E30.toString())); + spo_B02_E31 = new StatementImpl(vf.createURI("foo:event3"), pred1_atTime, vf.createLiteral(tvB02_E31.toString())); + spo_B02_E40 = new StatementImpl(vf.createURI("foo:event4"), pred1_atTime, vf.createLiteral(tvB02_E40.toString())); + spo_B03_E20 = new StatementImpl(vf.createURI("foo:event5"), pred1_atTime, vf.createLiteral(tvB03_E20.toString())); + spo_B29_E30 = new StatementImpl(vf.createURI("foo:event1"), pred1_atTime, vf.createLiteral(tvB29_E30.toString())); + spo_B30_E32 = new StatementImpl(vf.createURI("foo:event1"), pred1_atTime, vf.createLiteral(tvB30_E32.toString())); + spo_B02 = new StatementImpl(vf.createURI("foo:event6"), pred1_atTime, vf.createLiteral(tsB02.getAsReadable())); + + // Create statements about time instants 0 - 40 seconds + for (int i = 0; i < seriesTs.length; i++) { + seriesSpo[i] = new StatementImpl(vf.createURI("foo:event0" + i), pred1_atTime, vf.createLiteral(seriesTs[i].getAsReadable())); + } + + } + + /** + * @throws java.lang.Exception + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + } + + /** + * Create a table for test after deleting it. + */ + private static void createTable(Configuration conf, String tablename) + throws AccumuloException, AccumuloSecurityException, TableNotFoundException, TableExistsException { + TableOperations tableOps = ConfigUtils.getConnector(conf).tableOperations(); + if (tableOps.exists(tablename)) { + tableOps.delete(tablename); + } + tableOps.create(tablename); + } + + /** + * @throws java.lang.Exception + */ + @AfterClass + public static void tearDownAfterClass() throws Exception { + } + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + conf = new Configuration(); + conf.setBoolean(ConfigUtils.USE_MOCK_INSTANCE, true); + conf.set(ConfigUtils.TEMPORAL_TABLENAME, uniquePerTestTemporalIndexTableName); + // This is from http://linkedevents.org/ontology + // and http://motools.sourceforge.net/event/event.html + conf.setStrings(ConfigUtils.TEMPORAL_PREDICATES_LIST, "" + + URI_PROPERTY_AT_TIME + "," + + URI_PROPERTY_CIRCA + "," + + URI_PROPERTY_EVENT_TIME); + + // delete and create table + createTable(conf, uniquePerTestTemporalIndexTableName); + tIndexer = new AccumuloTemporalIndexer(); + tIndexer.setConf(conf); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + tIndexer.close(); + TableOperations tableOps = ConfigUtils.getConnector(conf).tableOperations(); + + if (tableOps.exists(uniquePerTestTemporalIndexTableName)) + tableOps.delete(uniquePerTestTemporalIndexTableName); + } + + /** + * Test method for {@link AccumuloTemporalIndexer#TemporalIndexerImpl(org.apache.hadoop.conf.Configuration)} . + * + * @throws TableExistsException + * @throws TableNotFoundException + * @throws AccumuloSecurityException + * @throws AccumuloException + * @throws IOException + */ + @Test + public void testTemporalIndexerImpl() + throws AccumuloException, AccumuloSecurityException, TableNotFoundException, TableExistsException, IOException { + assertNotNull("Constructed.", tIndexer.toString()); + } + + /** + * Test method for {@link AccumuloTemporalIndexer#storeStatement(convertStatement(org.openrdf.model.Statement)} + * + * @throws NoSuchAlgorithmException + */ + @Test + public void testStoreStatement() throws IOException, AccumuloException, AccumuloSecurityException, TableNotFoundException, TableExistsException, NoSuchAlgorithmException { + // count rows expected to store: + int rowsStoredExpected = 0; + + ValueFactory vf = new ValueFactoryImpl(); + + URI pred1_atTime = vf.createURI(URI_PROPERTY_AT_TIME); + URI pred2_circa = vf.createURI(URI_PROPERTY_CIRCA); + + // Should not be stored because they are not in the predicate list + String validDateStringWithThirteens = "1313-12-13T13:13:13Z"; + tIndexer.storeStatement(convertStatement(new StatementImpl(vf.createURI("foo:subj1"), RDFS.LABEL, vf.createLiteral(validDateStringWithThirteens)))); + + // Test: Should not store an improper date, and log a warning (log warning not tested). + final String invalidDateString = "ThisIsAnInvalidDate"; +// // Silently logs a warning for bad dates. Old: Set true when we catch the error: +// boolean catchErrorThrownCorrectly = false; +// try { + tIndexer.storeStatement(convertStatement(new StatementImpl(vf.createURI("foo:subj2"), pred1_atTime, vf.createLiteral(invalidDateString)))); +// } catch (IllegalArgumentException e) { +// catchErrorThrownCorrectly = true; +// Assert.assertTrue( +// "Invalid date parse error should include the invalid string. message=" + e.getMessage(), +// e.getMessage().contains(invalidDateString)); +// } +// Assert.assertTrue("Invalid date parse error should be thrown for this bad date=" + invalidDateString, catchErrorThrownCorrectly); + + // These are different datetimes instant but from different time zones. + // This is an arbitrary zone, BRST=Brazil, better if not local. + // same as "2015-01-01T01:59:59Z" + final String testDate2014InBRST = "2014-12-31T23:59:59-02:00"; + // next year, same as "2017-01-01T01:59:59Z" + final String testDate2016InET = "2016-12-31T20:59:59-05:00"; + + // These should be stored because they are in the predicate list. + // BUT they will get converted to the same exact datetime in UTC. + Statement s3 = new StatementImpl(vf.createURI("foo:subj3"), pred1_atTime, vf.createLiteral(testDate2014InBRST)); + Statement s4 = new StatementImpl(vf.createURI("foo:subj4"), pred2_circa, vf.createLiteral(testDate2016InET)); + tIndexer.storeStatement(convertStatement(s3)); + rowsStoredExpected++; + tIndexer.storeStatement(convertStatement(s4)); + rowsStoredExpected++; + + // This should not be stored because the object is not a literal + tIndexer.storeStatement(convertStatement(new StatementImpl(vf.createURI("foo:subj5"), pred1_atTime, vf.createURI("in:valid")))); + + tIndexer.flush(); + + int rowsStoredActual = printTables("junit testing: Temporal entities stored in testStoreStatement", null, null); + Assert.assertEquals("Number of rows stored.", rowsStoredExpected*4, rowsStoredActual); // 4 index entries per statement + + } + + @Test + public void testStoreStatementWithInterestingLiterals() throws Exception { + ValueFactory vf = new ValueFactoryImpl(); + + URI pred1_atTime = vf.createURI(URI_PROPERTY_AT_TIME); + + tIndexer.storeStatement(convertStatement(new StatementImpl( + vf.createURI("foo:subj2"), + pred1_atTime, + vf.createLiteral("A number of organizations located, gathered, or classed together. [Derived from Concise Oxford English Dictionary, 11th Edition, 2008]")))); + + int rowsStoredActual = printTables("junit testing: Temporal entities stored in testStoreStatement", null, null); + Assert.assertEquals("Number of rows stored.", 0, rowsStoredActual); // 4 index entries per statement + } + + /** + * Test method for {@link AccumuloTemporalIndexer#storeStatement(convertStatement(org.openrdf.model.Statement)} + * + * @throws NoSuchAlgorithmException + */ + @Test + public void testStoreStatementBadInterval() throws IOException, AccumuloException, AccumuloSecurityException, TableNotFoundException, TableExistsException, NoSuchAlgorithmException { + // count rows expected to store: + int rowsStoredExpected = 0; + + ValueFactory vf = new ValueFactoryImpl(); + URI pred1_atTime = vf.createURI(URI_PROPERTY_AT_TIME); + + // Test: Should not store an improper date interval, and log a warning (log warning not tested). + final String invalidDateIntervalString="[bad,interval]"; + // Silently logs a warning for bad dates. + tIndexer.storeStatement(convertStatement(new StatementImpl(vf.createURI("foo:subj1"), pred1_atTime, vf.createLiteral(invalidDateIntervalString)))); + + final String validDateIntervalString="[2016-12-31T20:59:59-05:00,2016-12-31T21:00:00-05:00]"; + tIndexer.storeStatement(convertStatement(new StatementImpl(vf.createURI("foo:subj2"), pred1_atTime, vf.createLiteral(validDateIntervalString)))); + rowsStoredExpected++; + + tIndexer.flush(); + + int rowsStoredActual = printTables("junit testing: Temporal intervals stored in testStoreStatement", null, null); + Assert.assertEquals("Only good intervals should be stored.", rowsStoredExpected*2, rowsStoredActual); // 2 index entries per interval statement + } + + @Test + public void testStoreStatementsSameTime() throws IOException, NoSuchAlgorithmException, AccumuloException, AccumuloSecurityException, TableNotFoundException, TableExistsException + { + ValueFactory vf = new ValueFactoryImpl(); + URI pred1_atTime = vf.createURI(URI_PROPERTY_AT_TIME); + URI pred2_circa = vf.createURI(URI_PROPERTY_CIRCA); + + // These are the same datetime instant but from different time + // zones. + // This is an arbitrary zone, BRST=Brazil, better if not local. + final String ZONETestDateInBRST = "2014-12-31T23:59:59-02:00"; + final String ZONETestDateInZulu = "2015-01-01T01:59:59Z"; + final String ZONETestDateInET = "2014-12-31T20:59:59-05:00"; + + // These all should be stored because they are in the predicate list. + // BUT they will get converted to the same exact datetime in UTC. + // So we have to make the key distinct! Good luck indexer! + Statement s1 = new StatementImpl(vf.createURI("foo:subj1"), pred2_circa, vf.createLiteral(ZONETestDateInET)); + Statement s2 = new StatementImpl(vf.createURI("foo:subj2"), pred1_atTime, vf.createLiteral(ZONETestDateInZulu)); + Statement s3 = new StatementImpl(vf.createURI("foo:subj3"), pred1_atTime, vf.createLiteral(ZONETestDateInBRST)); + int rowsStoredExpected = 0; + tIndexer.storeStatement(convertStatement(s1)); + rowsStoredExpected++; + tIndexer.storeStatement(convertStatement(s2)); + rowsStoredExpected++; + tIndexer.storeStatement(convertStatement(s3)); + rowsStoredExpected++; + int rowsStoredActual = printTables("junit testing: Duplicate times stored", null /*System.out*/, null); + Assert.assertEquals("Number of Duplicate times stored, 1 means duplicates not handled correctly.", rowsStoredExpected*4, rowsStoredActual); + } + + /** + * Test method for {@link AccumuloTemporalIndexer#storeStatements(java.util.Collection)} . + * + * @throws TableExistsException + * @throws TableNotFoundException + * @throws AccumuloSecurityException + * @throws AccumuloException + * @throws IOException + * @throws IllegalArgumentException + * @throws NoSuchAlgorithmException + */ + @Test + public void testStoreStatements() + throws AccumuloException, AccumuloSecurityException, TableNotFoundException, TableExistsException, IllegalArgumentException, IOException, + NoSuchAlgorithmException { + long valueHash = 0; + Collection<Statement> statements = new ArrayList<Statement>(70); + statements.addAll(Arrays.asList(seriesSpo)); + int rowsStoredExpected = statements.size()*4; // instants store 4 each + // hash the expected output: + for (Statement statement : statements) { + valueHash = hasher(valueHash, StringUtils.getBytesUtf8(StatementSerializer.writeStatement(statement))); + valueHash = hasher(valueHash, StringUtils.getBytesUtf8(StatementSerializer.writeStatement(statement))); + valueHash = hasher(valueHash, StringUtils.getBytesUtf8(StatementSerializer.writeStatement(statement))); + valueHash = hasher(valueHash, StringUtils.getBytesUtf8(StatementSerializer.writeStatement(statement))); + } + statements.add(spo_B02_E30); + rowsStoredExpected += 2; // intervals store two dates + statements.add(spo_B30_E32); + rowsStoredExpected += 2; // intervals store two dates + valueHash = hasher(valueHash, StringUtils.getBytesUtf8(StatementSerializer.writeStatement(spo_B02_E30))); + valueHash = hasher(valueHash, StringUtils.getBytesUtf8(StatementSerializer.writeStatement(spo_B02_E30))); + valueHash = hasher(valueHash, StringUtils.getBytesUtf8(StatementSerializer.writeStatement(spo_B30_E32))); + valueHash = hasher(valueHash, StringUtils.getBytesUtf8(StatementSerializer.writeStatement(spo_B30_E32))); + // duplicates will overwrite old ones, no change in the output except timestamps + statements.add(spo_B30_E32); + statements.add(spo_B30_E32); + + List<RyaStatement> ryaStatements = Lists.newArrayList(); + for (Statement s : statements){ ryaStatements.add(convertStatement(s));} + tIndexer.storeStatements(ryaStatements); + + Map<String, Long> statistics = new HashMap<String, Long>(); + int rowsStoredActual = printTables("junit testing: StoreStatements multiple statements", null, statistics); + Assert.assertEquals("Number of rows stored.", rowsStoredExpected, rowsStoredActual); // 4 index entries per statement + Assert.assertEquals("value hash.", valueHash, statistics.get(STAT_VALUEHASH).longValue()); + } + + /** + * test this classe's hash method to check un-ordered results. + */ + @Test + public void testSelfTestHashMethod() { + // self test on the hash method: + long hash01dup1 = hasher(0, new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + long hash01dup2 = hasher(0, new byte[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }); + Assert.assertEquals("same numbers, different sequence, hash should be the same.", hash01dup1, hash01dup2); + + // this one fails for sum hash, passes for XOR + long hash02dup1 = hasher(0, new byte[] { 123, 2, 1, 1 }); + hash02dup1 = hasher(hash02dup1, new byte[] { 123, 1, 1, 2 }); + long hash02dup2 = hasher(0, new byte[] { 123, 1, 1, 2 }); + hash02dup2 = hasher(hash02dup2, new byte[] { 123, 1, 3, 0, 0 }); + Assert.assertTrue("Different numbers, should be different hashes: " + hash02dup1 + " != " + hash02dup2, hash02dup1 != hash02dup2); + } + /** + * Test instant equal to a given instant. + * From the series: instant {equal, before, after} instant + * @throws AccumuloSecurityException + * @throws AccumuloException + * @throws TableNotFoundException + */ + @Test + public void testQueryInstantEqualsInstant() throws IOException, QueryEvaluationException, TableNotFoundException, AccumuloException, AccumuloSecurityException { + // tiB02_E30 read as: Begins 2 seconds, ends at 30 seconds + // these should not match as they are not instances. + tIndexer.storeStatement(convertStatement(spo_B03_E20)); + tIndexer.storeStatement(convertStatement(spo_B02_E30)); + tIndexer.storeStatement(convertStatement(spo_B02_E40)); + tIndexer.storeStatement(convertStatement(spo_B02_E31)); + tIndexer.storeStatement(convertStatement(spo_B30_E32)); + int expectedStoreCount = 5 * 2; // two entries for intervals + + // seriesSpo[s] and seriesTs[s] are statements and instant for s seconds after the uniform time. + int searchForSeconds = 5; + int expectedResultCount = 1; + for (int s = 0; s <= searchForSeconds + 3; s++) { // <== logic here + tIndexer.storeStatement(convertStatement(seriesSpo[s])); + expectedStoreCount+=4; //4 entries per statement. + } + tIndexer.flush(); + + int rowsStoredActual = printTables("junit testing: testQueryInstantEqualsInstant 0 to 8 seconds and 5 intervals stored. expectedStoreCount="+expectedStoreCount, null /*System.out*/, null); + Assert.assertEquals("Should find count of rows.", expectedStoreCount, rowsStoredActual); + + CloseableIteration<Statement, QueryEvaluationException> iter; + iter = tIndexer.queryInstantEqualsInstant(seriesTs[searchForSeconds], EMPTY_CONSTRAINTS); // <== logic here + int count = 0; + while (iter.hasNext()) { + Statement s = iter.next(); + Statement nextExpectedStatement = seriesSpo[searchForSeconds]; // <== logic here + assertTrue("Should match: " + nextExpectedStatement + " == " + s, nextExpectedStatement.equals(s)); + count++; + } + Assert.assertEquals("Should find count of rows.", expectedResultCount, count); + + } + + /** + * Test instant after a given instant. + * From the series: instant {equal, before, after} instant + * @throws AccumuloSecurityException + * @throws AccumuloException + * @throws TableNotFoundException + */ + @Test + public void testQueryInstantAfterInstant() throws IOException, QueryEvaluationException, TableNotFoundException, AccumuloException, AccumuloSecurityException { + // tiB02_E30 read as: Begins 2 seconds, ends at 30 seconds + // these should not match as they are not instances. + tIndexer.storeStatement(convertStatement(spo_B03_E20)); + tIndexer.storeStatement(convertStatement(spo_B02_E30)); + tIndexer.storeStatement(convertStatement(spo_B02_E40)); + tIndexer.storeStatement(convertStatement(spo_B02_E31)); + tIndexer.storeStatement(convertStatement(spo_B30_E32)); + + // seriesSpo[s] and seriesTs[s] are statements and instant for s seconds after the uniform time. + int searchForSeconds = 4; + int expectedResultCount = 9; + for (int s = 0; s <= searchForSeconds + expectedResultCount; s++) { // <== logic here + tIndexer.storeStatement(convertStatement(seriesSpo[s])); + } + tIndexer.flush(); + CloseableIteration<Statement, QueryEvaluationException> iter; + iter = tIndexer.queryInstantAfterInstant(seriesTs[searchForSeconds], EMPTY_CONSTRAINTS); + int count = 0; + while (iter.hasNext()) { + Statement s = iter.next(); + Statement nextExpectedStatement = seriesSpo[searchForSeconds + count + 1]; // <== logic here + assertTrue("Should match: " + nextExpectedStatement + " == " + s, nextExpectedStatement.equals(s)); + count++; + } + Assert.assertEquals("Should find count of rows.", expectedResultCount, count); + } + /** + * Test instant before a given instant. + * From the series: instant {equal, before, after} instant + */ + @Test + public void testQueryInstantBeforeInstant() throws IOException, QueryEvaluationException { + // tiB02_E30 read as: Begins 2 seconds, ends at 30 seconds + // these should not match as they are not instances. + tIndexer.storeStatement(convertStatement(spo_B03_E20)); + tIndexer.storeStatement(convertStatement(spo_B02_E30)); + tIndexer.storeStatement(convertStatement(spo_B02_E40)); + tIndexer.storeStatement(convertStatement(spo_B02_E31)); + tIndexer.storeStatement(convertStatement(spo_B30_E32)); + + // seriesSpo[s] and seriesTs[s] are statements and instant for s seconds after the uniform time. + int searchForSeconds = 4; + int expectedResultCount = 4; + for (int s = 0; s <= searchForSeconds + 15; s++) { // <== logic here + tIndexer.storeStatement(convertStatement(seriesSpo[s])); + } + tIndexer.flush(); + CloseableIteration<Statement, QueryEvaluationException> iter; + + iter = tIndexer.queryInstantBeforeInstant(seriesTs[searchForSeconds], EMPTY_CONSTRAINTS); + int count = 0; + while (iter.hasNext()) { + Statement s = iter.next(); + Statement nextExpectedStatement = seriesSpo[count]; // <== logic here + assertTrue("Should match: " + nextExpectedStatement + " == " + s, nextExpectedStatement.equals(s)); + count++; + } + Assert.assertEquals("Should find count of rows.", expectedResultCount, count); + } + + /** + * Test instant before given interval. + * From the series: Instance {before, after, inside} given Interval + */ + @Test + public void testQueryInstantBeforeInterval() throws IOException, QueryEvaluationException { + // tiB02_E30 read as: Begins 2 seconds, ends at 30 seconds + // these should not match as they are not instances. + tIndexer.storeStatement(convertStatement(spo_B03_E20)); + tIndexer.storeStatement(convertStatement(spo_B02_E30)); + tIndexer.storeStatement(convertStatement(spo_B02_E40)); + tIndexer.storeStatement(convertStatement(spo_B02_E31)); + tIndexer.storeStatement(convertStatement(spo_B30_E32)); + + // seriesSpo[s] and seriesTs[s] are statements and instants for s seconds after the uniform time. + TemporalInterval searchForSeconds = tvB02_E31; + int expectedResultCount = 2; // 00 and 01 seconds. + for (int s = 0; s <= 40; s++) { // <== logic here + tIndexer.storeStatement(convertStatement(seriesSpo[s])); + } + tIndexer.flush(); + CloseableIteration<Statement, QueryEvaluationException> iter; + iter = tIndexer.queryInstantBeforeInterval(searchForSeconds, EMPTY_CONSTRAINTS); + int count = 0; + while (iter.hasNext()) { + Statement s = iter.next(); + Statement nextExpectedStatement = seriesSpo[count]; // <== logic here + assertTrue("Should match: " + nextExpectedStatement + " == " + s, nextExpectedStatement.equals(s)); + count++; + } + Assert.assertEquals("Should find count of rows.", expectedResultCount, count); + } + + /** + * Test instant after given interval. + * Instance {before, after, inside} given Interval + */ + @Test + public void testQueryInstantAfterInterval() throws IOException, QueryEvaluationException { + // tiB02_E30 read as: Begins 2 seconds, ends at 30 seconds + // these should not match as they are not instances. + tIndexer.storeStatement(convertStatement(spo_B03_E20)); + tIndexer.storeStatement(convertStatement(spo_B02_E30)); + tIndexer.storeStatement(convertStatement(spo_B02_E40)); + tIndexer.storeStatement(convertStatement(spo_B02_E31)); + tIndexer.storeStatement(convertStatement(spo_B30_E32)); + + // seriesSpo[s] and seriesTs[s] are statements and instants for s seconds after the uniform time. + TemporalInterval searchAfterInterval = tvB02_E31; // from 2 to 31 seconds + int endingSeconds = 31; + int expectedResultCount = 9; // 32,33,...,40 seconds. + for (int s = 0; s <= endingSeconds + expectedResultCount; s++) { // <== logic here + tIndexer.storeStatement(convertStatement(seriesSpo[s])); + } + tIndexer.flush(); + CloseableIteration<Statement, QueryEvaluationException> iter; + iter = tIndexer.queryInstantAfterInterval(searchAfterInterval, EMPTY_CONSTRAINTS); + int count = 0; + while (iter.hasNext()) { + Statement s = iter.next(); + Statement nextExpectedStatement = seriesSpo[count + endingSeconds + 1]; // <== logic here + assertTrue("Should match: " + nextExpectedStatement + " == " + s, nextExpectedStatement.equals(s)); + count++; + } + Assert.assertEquals("Should find count of rows.", expectedResultCount, count); + } + + /** + * Test instant inside given interval. + * Instance {before, after, inside} given Interval + */ + @Test + public void testQueryInstantInsideInterval() throws IOException, QueryEvaluationException { + // tiB02_E30 read as: Begins 2 seconds, ends at 30 seconds + // these should not match as they are not instances. + tIndexer.storeStatement(convertStatement(spo_B03_E20)); + tIndexer.storeStatement(convertStatement(spo_B02_E30)); + tIndexer.storeStatement(convertStatement(spo_B02_E40)); + tIndexer.storeStatement(convertStatement(spo_B02_E31)); + tIndexer.storeStatement(convertStatement(spo_B30_E32)); + + // seriesSpo[s] and seriesTs[s] are statements and instants for s seconds after the uniform time. + TemporalInterval searchInsideInterval = tvB02_E31; // from 2 to 31 seconds + int beginningSeconds = 2; // <== logic here, and next few lines. + int endingSeconds = 31; + int expectedResultCount = endingSeconds - beginningSeconds - 1; // 3,4,...,30 seconds. + for (int s = 0; s <= 40; s++) { + tIndexer.storeStatement(convertStatement(seriesSpo[s])); + } + tIndexer.flush(); + CloseableIteration<Statement, QueryEvaluationException> iter; + iter = tIndexer.queryInstantInsideInterval(searchInsideInterval, EMPTY_CONSTRAINTS); + int count = 0; + while (iter.hasNext()) { + Statement s = iter.next(); + Statement nextExpectedStatement = seriesSpo[count + beginningSeconds + 1]; // <== logic here + assertTrue("Should match: " + nextExpectedStatement + " == " + s, nextExpectedStatement.equals(s)); + count++; + } + Assert.assertEquals("Should find count of rows.", expectedResultCount, count); + } + /** + * Test instant is the Beginning of the given interval. + * from the series: Instance {hasBeginning, hasEnd} Interval + */ + @Test + public void testQueryInstantHasBeginningInterval() throws IOException, QueryEvaluationException { + // tiB02_E30 read as: Begins 2 seconds, ends at 30 seconds + // these should not match as they are not instances. + tIndexer.storeStatement(convertStatement(spo_B03_E20)); + tIndexer.storeStatement(convertStatement(spo_B02_E30)); + tIndexer.storeStatement(convertStatement(spo_B02_E40)); + tIndexer.storeStatement(convertStatement(spo_B02_E31)); + tIndexer.storeStatement(convertStatement(spo_B30_E32)); + + // seriesSpo[s] and seriesTs[s] are statements and instants for s seconds after the uniform time. + TemporalInterval searchInsideInterval = tvB02_E31; // from 2 to 31 seconds + int searchSeconds = 2; // <== logic here, and next few lines. + int expectedResultCount = 1; // 2 seconds. + for (int s = 0; s <= 10; s++) { + tIndexer.storeStatement(convertStatement(seriesSpo[s])); + } + tIndexer.flush(); + CloseableIteration<Statement, QueryEvaluationException> iter; + iter = tIndexer.queryInstantHasBeginningInterval(searchInsideInterval, EMPTY_CONSTRAINTS); + int count = 0; + while (iter.hasNext()) { + Statement s = iter.next(); + Statement nextExpectedStatement = seriesSpo[searchSeconds]; // <== logic here + assertTrue("Should match: " + nextExpectedStatement + " == " + s, nextExpectedStatement.equals(s)); + count++; + } + Assert.assertEquals("Should find count of rows.", expectedResultCount, count); + } + /** + * Test instant is the end of the given interval. + * from the series: Instance {hasBeginning, hasEnd} Interval + */ + @Test + public void testQueryInstantHasEndInterval() throws IOException, QueryEvaluationException { + // tiB02_E30 read as: Begins 2 seconds, ends at 30 seconds + // these should not match as they are not instances. + tIndexer.storeStatement(convertStatement(spo_B03_E20)); + tIndexer.storeStatement(convertStatement(spo_B02_E30)); + tIndexer.storeStatement(convertStatement(spo_B02_E40)); + tIndexer.storeStatement(convertStatement(spo_B02_E31)); + tIndexer.storeStatement(convertStatement(spo_B30_E32)); + + // seriesSpo[s] and seriesTs[s] are statements and instants for s seconds after the uniform time. + TemporalInterval searchInsideInterval = tvB02_E31; // from 2 to 31 seconds + int searchSeconds = 31; // <== logic here, and next few lines. + int expectedResultCount = 1; // 31 seconds. + for (int s = 0; s <= 40; s++) { + tIndexer.storeStatement(convertStatement(seriesSpo[s])); + } + tIndexer.flush(); + CloseableIteration<Statement, QueryEvaluationException> iter; + iter = tIndexer.queryInstantHasEndInterval(searchInsideInterval, EMPTY_CONSTRAINTS); + int count = 0; + while (iter.hasNext()) { + Statement s = iter.next(); + Statement nextExpectedStatement = seriesSpo[searchSeconds]; // <== logic here + assertTrue("Should match: " + nextExpectedStatement + " == " + s, nextExpectedStatement.equals(s)); + count++; + } + Assert.assertEquals("Should find count of rows.", expectedResultCount, count); + } + + /** + * Test method for + * {@link mvm.rya.indexing.accumulo.temporal.AccumuloTemporalIndexer#queryIntervalEquals(TemporalInterval, StatementContraints)} + * . + * @throws IOException + * @throws QueryEvaluationException + * + */ + @Test + public void testQueryIntervalEquals() throws IOException, QueryEvaluationException { + // tiB02_E30 read as: Begins 2 seconds, ends at 30 seconds + tIndexer.storeStatement(convertStatement(spo_B03_E20)); + tIndexer.storeStatement(convertStatement(spo_B02_E30)); + tIndexer.storeStatement(convertStatement(spo_B02_E40)); + tIndexer.storeStatement(convertStatement(spo_B02_E31)); + tIndexer.storeStatement(convertStatement(spo_B30_E32)); + tIndexer.storeStatement(convertStatement(seriesSpo[4])); // instance at 4 seconds + tIndexer.flush(); + + CloseableIteration<Statement, QueryEvaluationException> iter; + iter = tIndexer.queryIntervalEquals(tvB02_E40, EMPTY_CONSTRAINTS); + // Should be found twice: + Assert.assertTrue("queryIntervalEquals: spo_B02_E40 should be found, but actually returned empty results. spo_B02_E40=" + spo_B02_E40, iter.hasNext()); + Assert.assertTrue("queryIntervalEquals: spo_B02_E40 should be found, but does not match.", spo_B02_E40.equals(iter.next())); + Assert.assertFalse("queryIntervalEquals: Find no more than one, but actually has more.", iter.hasNext()); + } + + /** + * Test interval before a given interval, for method: + * {@link AccumuloTemporalIndexer#queryIntervalBefore(TemporalInterval, StatementContraints)}. + * + * @throws IOException + * @throws QueryEvaluationException + */ + @Test + public void testQueryIntervalBefore() throws IOException, QueryEvaluationException { + // tiB02_E30 read as: Begins 2 seconds, ends at 30 seconds + tIndexer.storeStatement(convertStatement(spo_B00_E01)); + tIndexer.storeStatement(convertStatement(spo_B02_E30)); + tIndexer.storeStatement(convertStatement(spo_B02_E31)); + tIndexer.storeStatement(convertStatement(spo_B02_E40)); + tIndexer.storeStatement(convertStatement(spo_B03_E20)); + // instants should be ignored. + tIndexer.storeStatement(convertStatement(spo_B30_E32)); + tIndexer.storeStatement(convertStatement(seriesSpo[1])); // instance at 1 seconds + tIndexer.storeStatement(convertStatement(seriesSpo[2])); + tIndexer.storeStatement(convertStatement(seriesSpo[31])); + tIndexer.flush(); + + CloseableIteration<Statement, QueryEvaluationException> iter; + iter = tIndexer.queryIntervalBefore(tvB02_E31, EMPTY_CONSTRAINTS); + // Should be found twice: + Assert.assertTrue("spo_B00_E01 should be found, but actually returned empty results. spo_B00_E01=" + spo_B00_E01, iter.hasNext()); + Assert.assertTrue("spo_B00_E01 should be found, but found another.", spo_B00_E01.equals(iter.next())); + Assert.assertFalse("Find no more than one, but actually has more.", iter.hasNext()); + } + + /** + * interval is after the given interval. Find interval beginnings after the endings of the given interval. + * {@link AccumuloTemporalIndexer#queryIntervalAfter(TemporalInterval, StatementContraints). + * + * @throws IOException + * @throws QueryEvaluationException + */ + @Test + public void testQueryIntervalAfter() throws IOException, QueryEvaluationException { + // tiB02_E30 read as: Begins 2 seconds, ends at 30 seconds + tIndexer.storeStatement(convertStatement(spo_B00_E01)); + tIndexer.storeStatement(convertStatement(spo_B02_E29)); //<- after this one. + tIndexer.storeStatement(convertStatement(spo_B02_E30)); + tIndexer.storeStatement(convertStatement(spo_B02_E31)); + tIndexer.storeStatement(convertStatement(spo_B02_E40)); + tIndexer.storeStatement(convertStatement(spo_B03_E20)); + tIndexer.storeStatement(convertStatement(spo_B29_E30)); + tIndexer.storeStatement(convertStatement(spo_B30_E32)); + // instants should be ignored. + tIndexer.storeStatement(convertStatement(spo_B02)); + tIndexer.storeStatement(convertStatement(seriesSpo[1])); // instance at 1 seconds + tIndexer.storeStatement(convertStatement(seriesSpo[2])); + tIndexer.storeStatement(convertStatement(seriesSpo[31])); + tIndexer.flush(); + + CloseableIteration<Statement, QueryEvaluationException> iter; + iter = tIndexer.queryIntervalAfter(tvB02_E29, EMPTY_CONSTRAINTS); + // Should be found twice: + Assert.assertTrue("spo_B30_E32 should be found, but actually returned empty results. spo_B30_E32=" + spo_B30_E32, iter.hasNext()); + Statement s = iter.next(); + Assert.assertTrue("spo_B30_E32 should be found, but found another. spo_B30_E32="+spo_B30_E32+", but found="+s, spo_B30_E32.equals(s)); + Assert.assertFalse("Find no more than one, but actually has more.", iter.hasNext()); + + } + + /** + * Test instant after a given instant WITH two different predicates as constraints. + */ + @Test + public void testQueryWithMultiplePredicates() throws IOException, QueryEvaluationException { + // tiB02_E30 read as: Begins 2 seconds, ends at 30 seconds + // these should not match as they are not instances. + tIndexer.storeStatement(convertStatement(spo_B03_E20)); + tIndexer.storeStatement(convertStatement(spo_B02_E30)); + tIndexer.storeStatement(convertStatement(spo_B02_E40)); + tIndexer.storeStatement(convertStatement(spo_B02_E31)); + tIndexer.storeStatement(convertStatement(spo_B30_E32)); + + // seriesSpo[s] and seriesTs[s] are statements and instant for s seconds after the uniform time. + int searchForSeconds = 4; + int expectedResultCount = 9; + for (int s = 0; s <= searchForSeconds + expectedResultCount; s++) { // <== logic here + tIndexer.storeStatement(convertStatement(seriesSpo[s])); + } + ValueFactory vf = new ValueFactoryImpl(); + URI pred3_CIRCA_ = vf.createURI(URI_PROPERTY_CIRCA); // this one to ignore. + URI pred2_eventTime = vf.createURI(URI_PROPERTY_EVENT_TIME); + URI pred1_atTime = vf.createURI(URI_PROPERTY_AT_TIME); + + // add the predicate = EventTime ; Store in an array for verification. + Statement[] SeriesTs_EventTime = new Statement[expectedResultCount+1]; + for (int s = 0; s <= searchForSeconds + expectedResultCount; s++) { // <== logic here + Statement statement = new StatementImpl(vf.createURI("foo:EventTimeSubj0" + s), pred2_eventTime, vf.createLiteral(seriesTs[s].getAsReadable())); + tIndexer.storeStatement(convertStatement(statement)); + if (s>searchForSeconds) + SeriesTs_EventTime[s - searchForSeconds -1 ] = statement; + } + // add the predicate = CIRCA ; to be ignored because it is not in the constraints. + for (int s = 0; s <= searchForSeconds + expectedResultCount; s++) { // <== logic here + Statement statement = new StatementImpl(vf.createURI("foo:CircaEventSubj0" + s), pred3_CIRCA_, vf.createLiteral(seriesTs[s].getAsReadable())); + tIndexer.storeStatement(convertStatement(statement)); + } + tIndexer.flush(); + CloseableIteration<Statement, QueryEvaluationException> iter; + StatementContraints constraints = new StatementContraints(); + constraints.setPredicates(new HashSet<URI>(Arrays.asList( pred2_eventTime, pred1_atTime ))); + + iter = tIndexer.queryInstantAfterInstant(seriesTs[searchForSeconds], constraints); // EMPTY_CONSTRAINTS);// + int count_AtTime = 0; + int count_EventTime = 0; + while (iter.hasNext()) { + Statement s = iter.next(); + //System.out.println("testQueryWithMultiplePredicates result="+s); + Statement nextExpectedStatement = seriesSpo[searchForSeconds + count_AtTime + 1]; // <== logic here + if (s.getPredicate().equals(pred1_atTime)) { + assertTrue("Should match atTime: " + nextExpectedStatement + " == " + s, nextExpectedStatement.equals(s)); + count_AtTime++; + } + else if (s.getPredicate().equals(pred2_eventTime)) { + assertTrue("Should match eventTime: " + SeriesTs_EventTime[count_EventTime] + " == " + s, SeriesTs_EventTime[count_EventTime].equals(s)); + count_EventTime++; + } else { + assertTrue("This predicate should not be returned: "+s, false); + } + + } + + Assert.assertEquals("Should find count of atTime rows.", expectedResultCount, count_AtTime); + Assert.assertEquals("Should find count of eventTime rows.", expectedResultCount, count_EventTime); + } + + + /** + * Test method for {@link AccumuloTemporalIndexer#getIndexablePredicates()} . + * + * @throws TableExistsException + * @throws TableNotFoundException + * @throws AccumuloSecurityException + * @throws AccumuloException + * @throws IOException + */ + @Test + public void testGetIndexablePredicates() throws AccumuloException, AccumuloSecurityException, TableNotFoundException, TableExistsException, IOException { + Set<URI> p = tIndexer.getIndexablePredicates(); + Assert.assertEquals("number of predicates returned:", 3, p.size()); + } + + /** + * Count all the entries in the temporal index table, return the count. + * Uses printTables for reliability. + * + */ + public int countAllRowsInTable() throws AccumuloException, AccumuloSecurityException, TableNotFoundException, NoSuchAlgorithmException { + return printTables("Counting rows.", null, null); + } + + /** + * Print and gather statistics on the entire index table. + * + * @param description + * Printed to the console to find the test case. + * @param out + * null or System.out or other output to send a listing. + * @param statistics + * Hashes, sums, and counts for assertions. + * @return Count of entries in the index table. + */ + public int printTables(String description, PrintStream out, Map<String, Long> statistics) + throws TableNotFoundException, AccumuloException, AccumuloSecurityException + { + if (out == null) { + out = new PrintStream(new NullOutputStream()); + } + out.println("-- start printTables() -- " + description); + String FORMAT = "%-20s %-20s %-40s %-40s\n"; + int rowsPrinted = 0; + long keyHasher = 0; + long valueHasher = 0; + out.println("Reading : " + this.uniquePerTestTemporalIndexTableName); + out.format(FORMAT, "--Row--", "--ColumnFamily--", "--ColumnQualifier--", "--Value--"); + + Scanner s = ConfigUtils.getConnector(conf).createScanner(this.uniquePerTestTemporalIndexTableName, Constants.NO_AUTHS); + for (Entry<Key, org.apache.accumulo.core.data.Value> entry : s) { + rowsPrinted++; + Key k = entry.getKey(); + out.format(FORMAT, toHumanString(k.getRow()), + toHumanString(k.getColumnFamily()), + toHumanString(k.getColumnQualifier()), + toHumanString(entry.getValue())); + keyHasher = hasher(keyHasher, (StringUtils.getBytesUtf8(entry.getKey().toStringNoTime()))); + valueHasher = hasher(valueHasher, (entry.getValue().get())); + } + out.println(); + // } + + if (statistics != null) { + statistics.put(STAT_COUNT, (long) rowsPrinted); + statistics.put(STAT_KEYHASH, keyHasher); + statistics.put(STAT_VALUEHASH, valueHasher); + } + + return rowsPrinted; + + } + + /** + * Order independent hashcode. + * Read more: http://stackoverflow.com/questions/18021643/hashing-a-set-of-integers-in-an-order-independent-way + * + * @param hashcode + * @param list + * @return + */ + private static long hasher(long hashcode, byte[] list) { + long sum = 0; + for (byte val : list) { + sum += 1L + val; + } + hashcode ^= sum; + return hashcode; + } + + /** + * convert a non-utf8 byte[] and text and value to string and show unprintable bytes as {xx} where x is hex. + * @param value + * @return Human readable representation. + */ + static String toHumanString(Value value) { + return toHumanString(value==null?null:value.get()); + } + static String toHumanString(Text text) { + return toHumanString(text==null?null:text.copyBytes()); + } + static String toHumanString(byte[] bytes) { + if (bytes==null) + return "{null}"; + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + if ((b > 0x7e) || (b < 32)) { + sb.append("{"); + sb.append(Integer.toHexString( b & 0xff )); // Lop off the sign extended ones. + sb.append("}"); + } else if (b == '{'||b == '}') { // Escape the literal braces. + sb.append("{"); + sb.append((char)b); + sb.append("}"); + } else + sb.append((char)b); + } + return sb.toString(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/temporal/TemporalInstantTest.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/temporal/TemporalInstantTest.java b/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/temporal/TemporalInstantTest.java new file mode 100644 index 0000000..06b4484 --- /dev/null +++ b/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/temporal/TemporalInstantTest.java @@ -0,0 +1,76 @@ +package mvm.rya.indexing.accumulo.temporal; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +import mvm.rya.indexing.TemporalInstant; + +import org.apache.commons.codec.binary.StringUtils; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.joda.time.format.ISODateTimeFormat; +import org.junit.Assert; +import org.junit.Test; + +public class TemporalInstantTest { + @Test + public void constructorTest() throws Exception { + TemporalInstant instant = new TemporalInstantRfc3339(2014, 12, 30, // + 12, 59, 59); + // YYYY-MM-DDThh:mm:ssZ + String stringTestDate01 = "2014-12-30T12:59:59Z"; + Date dateTestDate01 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX") + .parse(stringTestDate01); + Assert.assertEquals(stringTestDate01, instant.getAsKeyString()); + Assert.assertArrayEquals(StringUtils.getBytesUtf8(instant.getAsKeyString()), instant.getAsKeyBytes()); + Assert.assertTrue("Key must be normalized to time zone Zulu",instant.getAsKeyString().endsWith("Z")); + // show the local time us. + // Warning, if test is run in the London, or Zulu time zone, this test will be same as above, with the Z. + // TimeZone.setDefault(TimeZone.getTimeZone("UTC")); // this does not affect the library, don't use. + String stringLocalTestDate01 = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssXXX").format(dateTestDate01); + // for ET, will be: "2014-12-30T07:59:59-05:00" + //instant.getAsDateTime().withZone(null); +// System.out.println("===System.getProperty(user.timezone)="+System.getProperty("user.timezone")); //=ET +// System.out.println("===============TimeZone.getDefault()="+TimeZone.getDefault()); //=ET +// System.out.println("===========DateTimeZone.getDefault()="+DateTimeZone.getDefault()); //=UTC (wrong!) + // the timezone default gets set to UTC by some prior test, fix it here. + DateTimeZone newTimeZone = null; + try { + String id = System.getProperty("user.timezone"); + if (id != null) { + newTimeZone = DateTimeZone.forID(id); + } + } catch (RuntimeException ex) { + // ignored + } + if (newTimeZone == null) { + newTimeZone = DateTimeZone.forTimeZone(TimeZone.getDefault()); + } + DateTimeZone.setDefault(newTimeZone); + // null timezone means use the default: + Assert.assertEquals("Joda time library (actual) should use same local timezone as Java date (expected).", stringLocalTestDate01, instant.getAsReadable(null)); + } + @Test + public void zoneTestTest() throws Exception { + final String ZONETestDateInBRST = "2014-12-31T23:59:59-02:00"; // arbitrary zone, BRST=Brazil, better if not local. + final String ZONETestDateInZulu = "2015-01-01T01:59:59Z"; + final String ZONETestDateInET = "2014-12-31T20:59:59-05:00"; + TemporalInstant instant = new TemporalInstantRfc3339(DateTime.parse(ZONETestDateInBRST)); + + Assert.assertEquals("Test our test Zulu, ET strings.", ZONETestDateInET, DateTime.parse(ZONETestDateInZulu).withZone(DateTimeZone.forID("-05:00")).toString(ISODateTimeFormat.dateTimeNoMillis())); + Assert.assertEquals("Test our test BRST,Zulu strings.", ZONETestDateInZulu, DateTime.parse(ZONETestDateInBRST).withZone(DateTimeZone.UTC).toString(ISODateTimeFormat.dateTimeNoMillis())); + + Assert.assertTrue("Key must be normalized to time zone Zulu: "+instant.getAsKeyString(), instant.getAsKeyString().endsWith("Z")); + Assert.assertEquals("Key must be normalized from BRST -02:00", ZONETestDateInZulu, instant.getAsKeyString()); + Assert.assertArrayEquals(StringUtils.getBytesUtf8(instant.getAsKeyString()), instant.getAsKeyBytes()); + + Assert.assertTrue( "Ignore original time zone.", ! ZONETestDateInBRST.equals( instant.getAsReadable(DateTimeZone.forID("-07:00")))); + Assert.assertEquals( "Use original time zone.", ZONETestDateInBRST, instant.getAsDateTime().toString(TemporalInstantRfc3339.FORMATTER)); + Assert.assertEquals( "Time at specified time zone.", ZONETestDateInET, instant.getAsReadable(DateTimeZone.forID("-05:00"))); + + instant = new TemporalInstantRfc3339(DateTime.parse(ZONETestDateInZulu)); + Assert.assertEquals("expect a time with specified time zone.", ZONETestDateInET, instant.getAsReadable(DateTimeZone.forID("-05:00"))); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/92ddfa59/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/temporal/TemporalIntervalTest.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/temporal/TemporalIntervalTest.java b/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/temporal/TemporalIntervalTest.java new file mode 100644 index 0000000..3901cc9 --- /dev/null +++ b/extras/indexing/src/test/java/mvm/rya/indexing/accumulo/temporal/TemporalIntervalTest.java @@ -0,0 +1,158 @@ +package mvm.rya.indexing.accumulo.temporal; + +import java.util.Arrays; + +import mvm.rya.indexing.TemporalInstant; +import mvm.rya.indexing.TemporalInterval; + +import org.joda.time.DateTime; +import org.junit.Assert; +import org.junit.Test; + +public class TemporalIntervalTest { + @Test + public void constructorTest() throws Exception { + TemporalInterval ti = new TemporalInterval( // + new TemporalInstantRfc3339(2014, 12, 30, 12, 59, 59), // + new TemporalInstantRfc3339(2014, 12, 30, 13, 00, 00)); // + Assert.assertNotNull(ti.getAsKeyBeginning()); + Assert.assertNotNull(ti.getHasEnd()); + } + @Test + public void constructorBadArgTest() throws Exception { + // the end precedes the beginning: + try { + TemporalInterval ti = new TemporalInterval( // + new TemporalInstantRfc3339(2017, 12, 30, 12, 59, 59), // + new TemporalInstantRfc3339( 820, 12, 30, 12, 59, 59)); // the invention of algebra. + Assert.assertFalse("Constructor should throw an error if the beginning is after the end, but no error for interval:"+ti, true); + }catch (IllegalArgumentException e) { + // expected to catch this error. + } + } + + @Test + public void relationsTest() throws Exception { + + TemporalInterval ti01 = new TemporalInterval( + new TemporalInstantRfc3339(2015, 12, 30, 12, 59, 59), // + new TemporalInstantRfc3339(2016, 12, 30, 13, 00, 00)); // + + TemporalInterval ti02 = new TemporalInterval( + new TemporalInstantRfc3339(2015, 12, 30, 12, 59, 59), // + new TemporalInstantRfc3339(2016, 12, 30, 13, 00, 00)); // + + Assert.assertTrue("same constructor parameters, should be equal.", + ti01.equals(ti02)); + Assert.assertTrue( + "same constructor parameters, should compare 0 equal.", + 0 == ti01.compareTo(ti02)); + + } + + @Test + public void keyBeginTest() throws Exception { + // 58 seconds, earlier + TemporalInterval beginTI01 = new TemporalInterval( + new TemporalInstantRfc3339(2015, 12, 30, 12, 59, 58), // + new TemporalInstantRfc3339(2016, 12, 30, 13, 00, 00)); // + // 59 seconds, later + TemporalInterval beginTI02 = new TemporalInterval( + new TemporalInstantRfc3339(2015, 12, 30, 12, 59, 59), // + new TemporalInstantRfc3339(2016, 12, 30, 13, 00, 00)); // + + String key01b = Arrays.toString(beginTI01.getAsKeyBeginning()); + String key02b = Arrays.toString(beginTI02.getAsKeyBeginning()); + Assert.assertEquals("key02 is later so comparesTo = 1.", 1, key02b.compareTo(key01b)); + Assert.assertEquals("key01 is first so comparesTo = -1", -1, key01b.compareTo(key02b)); + + } + // These are shared for end test and compareTo tests. + // tiB03_E20 read as: Begins 3 seconds, ends at 20 seconds + final TemporalInterval tiB03_E20 = new TemporalInterval(// + new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 03), // + new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 20)); + // 30 seconds, Begins earlier, ends later + final TemporalInterval tiB02_E30 = new TemporalInterval(// + new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 02), // + new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 30)); + // 30 seconds, same as above + final TemporalInterval tiB02_E30Dup = new TemporalInterval(// + new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 02), // + new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 30)); + // 30 seconds, same as above, but ends later + final TemporalInterval tiB02_E31 = new TemporalInterval(// + new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 02), // + new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 31)); + + @Test + public void CompareToTest() throws Exception { + + Assert.assertEquals("interval tiB03_E20.compareTo(tiB02_E30), B03 starts later(greater) so comparesTo = 1.", 1, tiB03_E20.compareTo(tiB02_E30)); + Assert.assertEquals("interval tiB02_E30.compareTo(tiB03_E20), B02 starts first(lesser) so comparesTo = -1", -1, tiB02_E30.compareTo(tiB03_E20)); + Assert.assertEquals("interval tiB02_E30.compareTo(tiB02_E31), E30 ends first so comparesTo = -1", -1, tiB02_E30.compareTo(tiB02_E31)); + Assert.assertEquals("interval tiB02_E30.compareTo(tiB02_E30Dup) same so comparesTo = 0", 0, tiB02_E30.compareTo(tiB02_E30Dup)); + } + @Test + public void EqualsTest() throws Exception { + Object notATemporalInterval = "Iamastring."; + Assert.assertFalse("interval tiB02_E30.equals(tiB02_E31) differ so equals() is false.", tiB02_E30.equals(notATemporalInterval)); + Assert.assertFalse("interval tiB02_E30.equals(tiB02_E31) differ so equals() is false.", tiB02_E30.equals(tiB02_E31)); + Assert.assertTrue ("interval tiB02_E30.equals(tiB02_E30Dup) same so equals() is true.", tiB02_E30.equals(tiB02_E30Dup)); + } + @Test + public void keyEndTest() throws Exception { + String keyB03_E20 = new String( tiB03_E20.getAsKeyEnd(), "US-ASCII"); + String keyB02_E30 = new String(tiB02_E30.getAsKeyEnd(), "US-ASCII"); + String keyB02_E30Dup = new String(tiB02_E30Dup.getAsKeyEnd(), "US-ASCII"); + + Assert.assertEquals("End keyB02_E30.compareTo(keyB03_E20), E30 is later = 1. key="+keyB02_E30, 1, keyB02_E30.compareTo(keyB03_E20)); + Assert.assertEquals("End keyB03_E20.compareTo(keyB02_E30), E20 is first = -1", -1, keyB03_E20.compareTo(keyB02_E30)); + Assert.assertEquals("End keyB02_E30.compareTo(keyB02_E30Dup) same so comparesTo = 0", 0, keyB02_E30.compareTo(keyB02_E30Dup)); + } + + + + @Test + public void infinitePastFutureAlwaysTest() throws Exception { + final TemporalInstant TestDateString = new TemporalInstantRfc3339(new DateTime("2015-01-01T01:59:59Z")); + TemporalInterval tvFuture = new TemporalInterval(TestDateString,TemporalInstantRfc3339.getMaximumInstance()); + TemporalInterval tvPast = new TemporalInterval(TemporalInstantRfc3339.getMinimumInstance(), TestDateString); + TemporalInterval tvAlways = new TemporalInterval(TemporalInstantRfc3339.getMinimumInstance(), TemporalInstantRfc3339.getMaximumInstance()); + Assert.assertTrue("The future is greater (starts after) than the past for compareTo().", tvFuture.compareTo(tvPast) > 0); + Assert.assertTrue("The future is greater (starts after) than always for compareTo().", tvFuture.compareTo(tvAlways) > 0); + Assert.assertTrue("The past is less (starts same, ends earlier) than always for compareTo().", tvFuture.compareTo(tvPast) > 0); + + } + @Test + public void hashTest() throws Exception { + // Use MAX to see how it handles overflowing values. Should silently go negative. + int hashcode01Same = (new TemporalInterval(new TemporalInstantRfc3339(new DateTime(Integer.MAX_VALUE / 2)), new TemporalInstantRfc3339(new DateTime(Integer.MAX_VALUE)))).hashCode(); + int hashcode02Same = (new TemporalInterval(new TemporalInstantRfc3339(new DateTime(Integer.MAX_VALUE / 2)), new TemporalInstantRfc3339(new DateTime(Integer.MAX_VALUE)))).hashCode(); + int hashcode03Diff = (new TemporalInterval(new TemporalInstantRfc3339(new DateTime(Integer.MAX_VALUE / 2)), new TemporalInstantRfc3339(new DateTime(Integer.MAX_VALUE)))).hashCode(); + int hashcode04Diff = (new TemporalInterval(new TemporalInstantRfc3339(new DateTime(Integer.MIN_VALUE )), new TemporalInstantRfc3339(new DateTime(Integer.MIN_VALUE)))).hashCode(); + int hashcode05Diff = (new TemporalInterval(new TemporalInstantRfc3339(new DateTime(Integer.MAX_VALUE )), new TemporalInstantRfc3339(new DateTime(Integer.MAX_VALUE)))).hashCode(); + int hashcode06Diff = (new TemporalInterval(new TemporalInstantRfc3339(new DateTime(0)), new TemporalInstantRfc3339(new DateTime( 0)))).hashCode(); + int hashcode07Diff = (new TemporalInterval(new TemporalInstantRfc3339(new DateTime(1000)), new TemporalInstantRfc3339(new DateTime( 1000)))).hashCode(); + int hashcode08Diff = (new TemporalInterval(new TemporalInstantRfc3339(new DateTime(0)), new TemporalInstantRfc3339(new DateTime( 1000)))).hashCode(); + int hashcode09Diff = (new TemporalInterval((TemporalInstantRfc3339.getMinimumInstance()),(TemporalInstantRfc3339.getMaximumInstance()) )).hashCode(); + int hashcode10Diff = (new TemporalInterval(new TemporalInstantRfc3339(new DateTime(0)) ,(TemporalInstantRfc3339.getMaximumInstance()) )).hashCode(); + Assert.assertEquals("Same input should produce same hashcode. (always!)", hashcode01Same , hashcode02Same); + + Assert.assertTrue("Different small input should produce different hashcode. (usually!) hashcodes:" + +hashcode03Diff+" "+hashcode04Diff+" "+hashcode03Diff+" "+hashcode05Diff, + hashcode03Diff != hashcode04Diff && hashcode03Diff != hashcode05Diff); + + Assert.assertTrue("Different large input should produce different hashcode. (usually!) hashcodes:" + +hashcode06Diff +" "+ hashcode07Diff +" "+ hashcode06Diff +" "+ hashcode08Diff + +" key for date 0= "+(new TemporalInstantRfc3339(new DateTime(0))).getAsKeyString() + +" key for date 1000= "+(new TemporalInstantRfc3339(new DateTime(1000))).getAsKeyString(), + hashcode06Diff != hashcode07Diff && hashcode06Diff != hashcode08Diff); + Assert.assertTrue("Different max and min input should produce different hashcode. (usually!) hashcodes:" + +hashcode09Diff +" != "+ hashcode10Diff + +"fyi: key for date max= "+(TemporalInstantRfc3339.getMaximumInstance()).getAsKeyString() + + " key for date min= "+(TemporalInstantRfc3339.getMinimumInstance()).getAsKeyString(), + hashcode09Diff != hashcode10Diff ); + + } +}
