You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2017/09/28 11:08:42 UTC

[26/50] [abbrv] jena git commit: JENA-1396: Merge //github/afs/mantis as subdirectory jena-db/

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionLock.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionLock.java
index 0000000,0000000..ad87de7
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionLock.java
@@@ -1,0 -1,0 +1,71 @@@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements.  See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership.  The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++package org.seaborne.tdb2.store;
++
++import static org.junit.Assert.*;
++import org.junit.Rule;
++import org.junit.Test;
++import org.junit.rules.TemporaryFolder;
++import org.seaborne.dboe.base.file.AlreadyLocked;
++import org.seaborne.dboe.base.file.Location;
++import org.seaborne.dboe.base.file.ProcessFileLock;
++import org.seaborne.tdb2.sys.StoreConnection;
++
++/**
++ * Tests for {@link ProcessFileLock} in conjunction with {@link StoreConnection}s 
++ */
++public class TestStoreConnectionLock {
++    @Rule
++    public TemporaryFolder tempDir = new TemporaryFolder();
++    
++    @Test
++    public void lock_store_connection_01() {
++        Location dir = Location.create(tempDir.getRoot().getAbsolutePath());
++        ProcessFileLock lock = StoreConnection.lockForLocation(dir);
++        assertFalse(lock.isLockedHere());
++        
++        StoreConnection sConn = StoreConnection.connectCreate(dir);
++        assertEquals(dir, sConn.getLocation());
++        assertEquals(lock, sConn.getLock());
++        assertTrue(lock.isLockedHere());
++        
++        StoreConnection.release(dir);
++        assertFalse(lock.isLockedHere());
++    }
++    
++    @Test(expected=AlreadyLocked.class)
++    public void lock_store_connection_02() {
++        Location dir = Location.create(tempDir.getRoot().getAbsolutePath());
++        ProcessFileLock lock = StoreConnection.lockForLocation(dir);
++        lock.lockEx();
++        StoreConnection sConn = StoreConnection.connectCreate(dir);
++    }
++//        Location dir = Location.create(tempDir.getRoot().getAbsolutePath());
++//        // Creating a StoreConnection on the location will obtain the lock
++//         StoreConnection.make(dir);
++//        // Releasing the connection releases the lock
++//        StoreConnection.release(dir);
++//    }
++//
++//    @Test(expected = TDBException.class)
++//    public void location_lock_store_connection_02() throws IOException {
++//        Location dir = Location.create(tempDir.getRoot().getAbsolutePath());
++//        StoreConnection.make(dir);
++//    }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionMapped.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionMapped.java
index 0000000,0000000..ac3127a
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionMapped.java
@@@ -1,0 -1,0 +1,50 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store;
++
++import org.junit.AfterClass ;
++import org.junit.BeforeClass ;
++import org.seaborne.dboe.base.block.FileMode ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++import org.seaborne.tdb2.sys.TestOps ;
++
++/** Slow tests - complete cleaning of disk areas each time */
++public class TestStoreConnectionMapped extends AbstractTestStoreConnectionBasics
++{
++    static FileMode mode ;   
++
++    @BeforeClass
++    public static void beforeClassFileMode()
++    {
++        mode = SystemTDB.fileMode() ;
++        TestOps.setFileMode(FileMode.mapped) ;
++    }
++
++    @AfterClass
++    public static void afterClassFileMode()
++    {
++        TestOps.setFileMode(mode) ;
++    }
++
++    @Override
++    protected Location getLocation() {
++        return Location.create(ConfigTest.getCleanDir()) ;
++    }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionMem.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionMem.java
index 0000000,0000000..6da2c57
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestStoreConnectionMem.java
@@@ -1,0 -1,0 +1,28 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store;
++
++import org.seaborne.dboe.base.file.Location ;
++
++public class TestStoreConnectionMem extends AbstractTestStoreConnectionBasics
++{
++    @Override
++    protected Location getLocation() {
++        return Location.mem("TestStoreConnection") ;
++    }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestSuiteGraphTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestSuiteGraphTDB.java
index 0000000,0000000..cacbb35
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestSuiteGraphTDB.java
@@@ -1,0 -1,0 +1,40 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store;
++
++import junit.framework.TestSuite ;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.AllTests ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.junit.TestFactoryTDB ;
++
++/** Scripted test generation */
++
++@RunWith(AllTests.class)
++public class TestSuiteGraphTDB extends TestSuite
++{
++    static public TestSuite suite() { return new TestSuiteGraphTDB() ; }
++    
++    private TestSuiteGraphTDB()
++    {
++        super("TDB-Scripts") ;
++        String manifestMain = ConfigTest.getTestingDataRoot()+"/manifest.ttl" ;
++        TestFactoryTDB.make(this, manifestMain, "TDB-") ;
++    }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransPromoteTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransPromoteTDB.java
index 0000000,0000000..2814f32
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransPromoteTDB.java
@@@ -1,0 -1,0 +1,72 @@@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements.  See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership.  The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++package org.seaborne.tdb2.store;
++
++import org.apache.jena.sparql.core.DatasetGraph;
++import org.apache.log4j.Logger;
++import org.seaborne.dboe.transaction.txn.Transaction;
++import org.seaborne.dboe.transaction.txn.TransactionCoordinator;
++import org.seaborne.dboe.transaction.txn.TransactionException;
++import org.seaborne.tdb2.DatabaseMgr ;
++
++public class TestTransPromoteTDB extends AbstractTestTransPromoteTDB2 {
++
++    public TestTransPromoteTDB() {
++        super(getLoggers());
++    }
++
++    private static Logger[] getLoggers() {
++        return new Logger[]{ Logger.getLogger(Transaction.class) } ;
++    }
++    
++    @Override
++    protected void setPromotion(boolean b) {
++        TransactionCoordinator.promotion = b ;
++    }
++
++    @Override
++    protected boolean getPromotion() {
++        return TransactionCoordinator.promotion ;
++    }
++
++    @Override
++    protected void setReadCommitted(boolean b) {
++        TransactionCoordinator.readCommittedPromotion = b ;
++    }
++
++    @Override
++    protected boolean getReadCommitted() {
++        return TransactionCoordinator.readCommittedPromotion ;
++    }
++
++    @Override
++    protected Class<? extends Exception> getTransactionExceptionClass() {
++        return TransactionException.class;
++    }
++
++    @Override
++    protected DatasetGraph create() {
++        return DatabaseMgr.createDatasetGraph();
++    }
++
++    @Override
++    protected boolean supportsReadCommitted() {
++        return true;
++    }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactionLifecycleTDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactionLifecycleTDB.java
index 0000000,0000000..7f1add3
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactionLifecycleTDB.java
@@@ -1,0 -1,0 +1,33 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store;
++
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.sparql.transaction.AbstractTestTransactionLifecycle;
++import org.seaborne.tdb2.TDB2Factory ;
++
++/** Transaction tests - from ARQ */
++public class TestTransactionLifecycleTDB extends AbstractTestTransactionLifecycle
++{
++    @Override
++    protected Dataset create() {
++        return TDB2Factory.createDataset() ;
++    }
++}
++
++

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
index 0000000,0000000..1aed0a6
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTransactions.java
@@@ -1,0 -1,0 +1,204 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store;
++
++import java.io.StringReader ;
++import java.util.Iterator;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.StrUtils ;
++import org.apache.jena.query.Dataset ;
++import org.apache.jena.query.ReadWrite;
++import org.apache.jena.rdf.model.Model ;
++import org.apache.jena.rdf.model.Statement;
++import org.apache.jena.riot.Lang ;
++import org.apache.jena.riot.RDFDataMgr ;
++import org.apache.jena.sparql.core.Quad;
++import org.junit.After ;
++import org.junit.Before ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.dboe.transaction.txn.TransactionException;
++import org.seaborne.tdb2.TDB2Factory ;
++import org.seaborne.tdb2.sys.TDBInternal;
++
++/** Transactions and store connections - extended tests assuming the
++ * basics work. Hence these tests use memory databases. 
++ * 
++ * For tests of StoreConnection basics:
++ * @see AbstractTestStoreConnectionBasics
++ * @see TestStoreConnectionDirect
++ * @see TestStoreConnectionMapped
++ * @see TestStoreConnectionMem
++ */
++public class TestTransactions
++{
++    // Per-test unique-ish.
++    static int count = 0 ;
++    long x = System.currentTimeMillis()+(count++) ;
++    
++    String ns = "http://example/TestTransactions#" ;
++    String data1 = StrUtils.strjoinNL
++        ("prefix : <"+ns+">"
++        ,":s :p '000-"+x+"' ."
++        ,":s :p '111-"+x+"' ."
++        ," :g {"
++        ,"    :s :p '222-"+x+"' ."
++        ,"    :s :p '333-"+x+"' ."
++        ,"    :s :p '444-"+x+"' ."
++        ,"}"
++        ) ;
++    String data2 = StrUtils.strjoinNL
++        ("prefix : <"+ns+">"
++        ,":s :p 'AAA-"+x+"' ."
++        ,":s :p 'BBB-"+x+"' ."
++        ,":s :p 'CCC-"+x+"' ."
++        ,":s :p 'DDD-"+x+"' ."
++        ) ;
++    
++    Dataset dataset ; 
++    Location location ;
++    
++    @Before public void before() {
++        location = Location.mem() ;
++        dataset = TDB2Factory.connectDataset(location) ;
++    }
++
++    @After public void after() {
++        dataset.close() ;
++        TDBInternal.expel(dataset.asDatasetGraph());
++    }
++
++    // Models across transactions
++    @Test public void trans_01() {
++        Model named = dataset.getNamedModel(ns+"g") ;
++        Txn.executeWrite(dataset, ()->{
++            RDFDataMgr.read(dataset, new StringReader(data1), null, Lang.TRIG) ;
++        }) ;
++
++        Txn.executeRead(dataset, ()->{
++            long x1 = Iter.count(dataset.getDefaultModel().listStatements()) ;
++            assertEquals(2, x1) ;
++            long x2 = Iter.count(named.listStatements()) ;
++            assertEquals(3, x2) ;
++        }) ;
++        
++    }
++    
++    @Test public void trans_02() {
++        Model model = dataset.getDefaultModel() ;
++        Txn.executeWrite(dataset, ()->{
++            RDFDataMgr.read(model, new StringReader(data2), null, Lang.TURTLE) ;
++        }) ;
++        Txn.executeRead(dataset, ()->{
++            assertEquals(4, model.size()) ;
++        }) ;        
++    }
++    
++    // Iterators and trasnaxction scope.
++    
++    private void load(String data) { 
++        Txn.executeWrite(dataset, ()->{
++            RDFDataMgr.read(dataset, new StringReader(data), null, Lang.TURTLE) ;
++        }) ;
++    }
++    
++    public void iterator_01() {
++        load(data2);
++        
++        dataset.begin(ReadWrite.READ);
++        Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
++        Iter.consume(iter);
++        dataset.end();
++    }
++    
++    @Test(expected=TransactionException.class)
++    public void iterator_02() {
++        load(data2);
++        
++        dataset.begin(ReadWrite.READ);
++        Iterator<Quad> iter = dataset.asDatasetGraph().find();
++        dataset.end();
++        iter.next();
++    }
++    
++    @Test(expected=TransactionException.class)
++    public void iterator_03() {
++        load(data2);
++        
++        dataset.begin(ReadWrite.READ);
++        Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
++        dataset.end();
++        iter.next();
++    }
++
++    @Test(expected=TransactionException.class)
++    public void iterator_04() {
++        load(data2);
++        Iterator<Statement> iter = Txn.calculateRead(dataset, ()->dataset.getDefaultModel().listStatements());
++        iter.next();
++    }
++    
++    @Test(expected=TransactionException.class)
++    public void iterator_05() {
++        load(data2);
++        Iterator<Statement> iter = Txn.calculateWrite(dataset, ()->dataset.getDefaultModel().listStatements());
++        iter.next();
++    }
++
++    @Test(expected=TransactionException.class)
++    public void iterator_06() {
++        load(data2);
++        
++        dataset.begin(ReadWrite.READ);
++        Iterator<Quad> iter = dataset.asDatasetGraph().find();
++        dataset.end();
++        
++        dataset.begin(ReadWrite.READ);
++        iter.next();
++        dataset.end();
++    }
++    
++//    @Test
++//    public void iterator_07() {
++//        load(data2);
++//        
++//        // Isolated by copy.
++//        Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
++//        
++//        dataset.begin(ReadWrite.READ);
++//        iter.next();
++//        dataset.end();
++//    }
++//
++//    @Test
++//    public void iterator_08() {
++//        load(data2);
++//        
++//        // Isolated by copy.
++//        Iterator<Quad> iter = TDBInternal.getDatasetGraphTDB(dataset).find();
++//        
++//        dataset.begin(ReadWrite.READ);
++//        dataset.end();
++//        iter.next();
++//    }
++}
++
++

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTripleTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTripleTable.java
index 0000000,0000000..98e48d1
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/TestTripleTable.java
@@@ -1,0 -1,0 +1,132 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store;
++
++import java.util.Iterator ;
++
++import static org.junit.Assert.*;
++import org.apache.jena.graph.Node ;
++import org.apache.jena.graph.Triple ;
++import org.apache.jena.query.ReadWrite ;
++import org.apache.jena.sparql.util.NodeFactoryExtra ;
++import org.apache.log4j.Level ;
++import org.apache.log4j.Logger ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.setup.TDBBuilder ;
++
++public class TestTripleTable
++{
++    static {
++        Logger.getLogger("org.apache.jena.tdb.info").setLevel(Level.WARN) ;
++        Logger.getLogger("org.apache.jena.tdb.exec").setLevel(Level.WARN) ;
++    }
++
++    private static void add(TripleTable table, Node s, Node p, Node o)
++    {
++        table.add(new Triple(s,p,o)) ;
++    }
++
++    private static void notMatch(TripleTable table, Node s, Node p, Node o)
++    {
++        Iterator<Triple> iter = table.find(s, p, o) ;
++        assertNotNull(iter) ;
++        assertFalse(iter.hasNext()) ;
++    }
++
++    private static void match(TripleTable table, Node s, Node p, Node o)
++    {
++        Iterator<Triple> iter = table.find(s, p, o) ;
++        assertNotNull(iter) ;
++        assertTrue(iter.hasNext()) ;
++    }
++    
++    
++    private static void contains(TripleTable table, Node s, Node p, Node o)
++    {
++        Iterator<Triple> iter = table.find(s, p, o) ;
++        assertNotNull(iter) ;
++        assertTrue(iter.hasNext()) ;
++        assertEquals(new Triple(s, p, o), iter.next()) ;
++        assertFalse(iter.hasNext()) ;
++    }
++    
++    static Node n1 = NodeFactoryExtra.parseNode("<http://example/n1>") ;
++    static Node n2 = NodeFactoryExtra.parseNode("<http://example/n2>") ;
++    static Node n3 = NodeFactoryExtra.parseNode("<http://example/n3>") ;
++    static Node n4 = NodeFactoryExtra.parseNode("<http://example/n4>") ;
++    static Node n5 = NodeFactoryExtra.parseNode("<http://example/n5>") ;
++    static Node n6 = NodeFactoryExtra.parseNode("<http://example/n6>") ;
++    
++    @Test public void createTripleTable1()
++    { 
++        TripleTable table = createTripleTableMem() ; 
++        notMatch(table, n1, n2, n3) ;
++    }
++    
++    @Test public void add1()
++    { 
++        TripleTable table = createTripleTableMem() ;
++        table.add(new Triple(n1,n2,n3)) ;
++    }
++    
++    @Test public void find1()
++    { 
++        TripleTable table = createTripleTableMem() ;
++        add(table, n1, n2, n3) ;
++        contains(table, n1, n2, n3) ;
++        notMatch(table, n1, n2, n4) ;
++    }
++
++    @Test public void find2()
++    { 
++        TripleTable table = createTripleTableMem() ;
++        add(table, n1, n2, n3) ;
++        add(table, n1, n2, n4) ;
++        contains(table, n1, n2, n3) ;
++        contains(table, n1, n2, n4) ;
++    }
++
++    @Test public void find3()
++    { 
++        TripleTable table = createTripleTableMem() ;
++        add(table, n1, n2, n3) ;
++        add(table, n4, n5, n6) ;
++        contains(table, n1, n2, n3) ;
++        contains(table, n4, n5, n6) ;
++        notMatch(table, n1, n2, n4) ;
++    }
++
++    @Test public void find4()
++    { 
++        TripleTable table = createTripleTableMem() ;
++        add(table, n1, n2, n3) ;
++        add(table, n4, n5, n6) ;
++        match(table, Node.ANY, n2, n3) ;
++        match(table, null, n2, n3) ;
++        match(table, null, null, null) ;
++    }
++    
++    private TripleTable createTripleTableMem()
++    {
++        DatasetGraphTxn dsx = TDBBuilder.build(Location.mem()) ;
++        dsx.begin(ReadWrite.WRITE);
++        DatasetGraphTDB ds = (DatasetGraphTDB)dsx ;
++        return ds.getTripleTable() ;
++    }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/Test_SPARQL_TDB.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/Test_SPARQL_TDB.java
index 0000000,0000000..0ab4cb4
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/Test_SPARQL_TDB.java
@@@ -1,0 -1,0 +1,221 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store;
++
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.StrUtils ;
++import org.apache.jena.graph.Graph ;
++import org.apache.jena.graph.NodeFactory ;
++import org.apache.jena.graph.Triple ;
++import org.apache.jena.query.* ;
++import org.apache.jena.rdf.model.Model ;
++import org.apache.jena.sparql.sse.SSE ;
++import org.apache.jena.update.* ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.dboe.jenax.Txn ;
++import org.seaborne.tdb2.TDB2 ;
++import org.seaborne.tdb2.TDB2Factory ;
++
++/**
++ * Test SPARQL
++ */
++public class Test_SPARQL_TDB
++{
++    private static Dataset create() {
++        return TDB2Factory.createDataset() ;
++    }
++
++    private static Dataset create(Location location) {
++        return TDB2Factory.connectDataset(location) ;
++    }
++
++    private static String graphName = "http://example/" ;
++    private static Triple triple = SSE.parseTriple("(<x> <y> 123)") ;
++
++    // Standalone graph.
++    @Test public void sparql1()
++    {
++        // Test OpExecutor.execute(OpBGP) for a named graph used as a standalone model
++        Dataset ds = create() ;
++        add(ds, graphName, triple) ;
++        Txn.executeRead(ds, ()->{
++            Model m = ds.getNamedModel(graphName) ;
++            String qs = "SELECT * { ?s ?p ?o . }" ;
++            Query query = QueryFactory.create(qs) ;
++            QueryExecution qexec = QueryExecutionFactory.create(query, m) ;
++            ResultSet rs = qexec.execSelect() ;
++            ResultSetFormatter.consume(rs) ;
++        }) ;
++    }
++    
++    // Standalone graph.
++    @Test public void sparql2()
++    {
++        // Test OpExecutor.execute(OpFilter)for a named graph used as a standalone model
++        Dataset ds = create() ;
++        add(ds, graphName, triple) ;
++        
++        Txn.executeRead(ds, ()->{
++            Model m = ds.getNamedModel(graphName) ;
++            String qs = "SELECT * { ?s ?p ?o . FILTER ( ?o < 456 ) }" ;
++            Query query = QueryFactory.create(qs) ;
++            try(QueryExecution qexec = QueryExecutionFactory.create(query, m)) {
++                ResultSet rs = qexec.execSelect() ;
++                ResultSetFormatter.consume(rs) ;
++            }
++        }) ;
++    }
++    
++    // Requires OpDatasetNames 
++    @Test public void sparql3()
++    {
++        Dataset dataset = create() ;
++        // No triple added
++        Txn.executeRead(dataset, ()->{
++            Query query = QueryFactory.create("SELECT ?g { GRAPH ?g {} }") ;
++            QueryExecution qExec = QueryExecutionFactory.create(query, dataset) ;
++            ResultSet rs = qExec.execSelect() ;
++            int n = ResultSetFormatter.consume(rs) ;
++            assertEquals(0, n) ;
++        }) ;
++    }
++    
++    @Test public void sparql4()
++    {
++        Dataset dataset = create() ;
++        add(dataset, graphName, triple) ;
++        Txn.executeRead(dataset, ()->{
++            Query query = QueryFactory.create("SELECT ?g { GRAPH ?g {} }") ;
++            QueryExecution qExec = QueryExecutionFactory.create(query, dataset) ;
++            ResultSet rs = qExec.execSelect() ;
++            int n = ResultSetFormatter.consume(rs) ;
++            assertEquals(1, n) ;
++        }) ;
++    }
++    
++    @Test public void sparql5()
++    {
++        Dataset dataset = create() ;
++        add(dataset, graphName, triple);
++        Txn.executeRead(dataset, ()->{
++            Query query = QueryFactory.create("ASK { GRAPH <"+graphName+"> {} }") ;
++            boolean b = QueryExecutionFactory.create(query, dataset).execAsk() ;
++            assertEquals(true, b) ;
++        }) ;
++    }
++    
++    @Test public void sparql6()
++    {
++        Dataset dataset = create() ;
++        add(dataset, graphName, triple);
++        Txn.executeRead(dataset, ()->{
++            Query query = QueryFactory.create("ASK { GRAPH <http://example/x> {} }") ;
++            boolean b = QueryExecutionFactory.create(query, dataset).execAsk() ;
++            assertEquals(false, b) ;
++        }) ;
++    }
++
++    private static void add(Dataset dataset, String graphName, Triple triple) {
++        Txn.executeWrite(dataset, ()->{
++            Graph g2 = dataset.asDatasetGraph().getGraph(NodeFactory.createURI(graphName)) ;
++            g2.add(triple) ;
++        });
++    }
++    
++    // Test transactions effective.
++    
++    @Test public void sparql_txn_1()
++    {
++        Dataset dataset = create() ;
++        Txn.executeWrite(dataset, ()->{
++            update(dataset, "INSERT DATA { <x:s> <x:p> <x:o> }") ;
++        }) ;
++        // Explicit trasnaction steps.
++        dataset.begin(ReadWrite.READ) ;
++        try {
++            int n = count(dataset) ;
++            assertEquals(1, n) ;
++            n = count(dataset, "SELECT * { <x:s> <x:p> <x:o>}") ;
++            assertEquals(1, n) ;
++        } finally { dataset.end() ; }
++    }
++
++    @Test public void sparql_txn_2()
++    {
++        Dataset dataset1 = create(Location.mem("foo")) ;
++        Dataset dataset2 = create(Location.mem("foo")) ;
++        
++        Txn.executeWrite(dataset1, ()->{
++            update(dataset1, "INSERT DATA { <x:s> <x:p> <x:o> }") ;
++        }) ;
++        
++        Txn.executeRead(dataset1, ()->{
++            assertEquals(1, count(dataset1)) ;
++        }) ;
++        
++        // Same location.
++        Txn.executeRead(dataset2, ()->{
++            assertEquals(1, count(dataset2)) ;
++        }) ;
++    }
++
++    @Test public void sparql_update_unionGraph()
++    {
++        Dataset ds = TDB2Factory.createDataset() ;
++        // Update concrete default graph
++        Txn.executeWrite(ds, ()->{
++            ds.asDatasetGraph().add(SSE.parseQuad("(<g> <s> <p> 123)")) ;
++        }) ;
++        ds.getContext().setTrue(TDB2.symUnionDefaultGraph) ;
++            
++        Txn.executeWrite(ds, ()->{
++            // Update by looking in union graph
++            String us = StrUtils.strjoinNL(
++                "INSERT { GRAPH <http://example/g2> { ?s ?p 'NEW' } }",
++                "WHERE { ",
++                     "?s ?p 123",
++                " }" ) ;
++            UpdateRequest req = UpdateFactory.create(us) ;
++            UpdateAction.execute(req, ds) ;
++        }) ;
++                
++        Txn.executeRead(ds, ()->{
++            Model m = ds.getNamedModel("http://example/g2") ;
++            assertEquals("Did not find 1 statement in named graph", 1, m.size()) ;
++        }) ;
++    }
++    
++    private int count(Dataset dataset)
++    { return count(dataset, "SELECT * { ?s ?p ?o }") ; }
++    
++    private int count(Dataset dataset, String queryString)
++    
++    {
++        Query query = QueryFactory.create(queryString) ;
++        QueryExecution qExec = QueryExecutionFactory.create(query, dataset) ;
++        ResultSet rs = qExec.execSelect() ;
++        return ResultSetFormatter.consume(rs) ;
++    }
++    private void update(Dataset dataset, String string)
++    {
++        UpdateRequest req = UpdateFactory.create(string) ;
++        UpdateProcessor proc = UpdateExecutionFactory.create(req, dataset) ;
++        proc.execute() ;
++    }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/AbstractTestNodeTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/AbstractTestNodeTable.java
index 0000000,0000000..158e2ff
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/AbstractTestNodeTable.java
@@@ -1,0 -1,0 +1,66 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store.nodetable;
++
++import static org.junit.Assert.assertEquals ;
++import static org.junit.Assert.assertNotEquals ;
++import static org.junit.Assert.assertNotNull ;
++
++import org.apache.jena.graph.Node ;
++import org.apache.jena.sparql.util.NodeFactoryExtra ;
++import org.junit.Test ;
++import org.seaborne.tdb2.store.NodeId ;
++
++public abstract class AbstractTestNodeTable
++{
++    protected abstract NodeTable createEmptyNodeTable() ;
++    
++    protected void testNode(String str) {
++        testNode(NodeFactoryExtra.parseNode(str)) ;
++    }
++
++    protected void testNode(Node n) {
++        NodeTable nt = createEmptyNodeTable() ;
++        writeNode(nt, n) ;
++    }
++
++    protected static void writeNode(NodeTable nt, String str) {
++        writeNode(nt, NodeFactoryExtra.parseNode(str)) ;
++    }
++    
++    protected static void writeNode(NodeTable nt, Node n) {
++        NodeId nodeId = nt.getAllocateNodeId(n) ;
++        assertNotNull(nodeId) ;
++        assertNotEquals(NodeId.NodeDoesNotExist, nodeId) ;
++        assertNotEquals(NodeId.NodeIdAny, nodeId) ;
++
++        Node n2 = nt.getNodeForNodeId(nodeId) ;
++        assertEquals(n, n2) ;
++
++        NodeId nodeId2 = nt.getNodeIdForNode(n) ;
++        assertEquals(nodeId, nodeId2) ;
++    }
++
++    @Test public void nodetable_01()    { testNode("<http://example/x>") ; }
++    @Test public void nodetable_02()    { testNode("1") ; }
++    @Test public void nodetable_03()    { testNode("_:x") ; }
++    @Test public void nodetable_04()    { testNode("'x'") ; }
++    @Test public void nodetable_05()    { testNode("'x'@en") ; }
++    @Test public void nodetable_06()    { testNode("'x'^^<http://example/dt>") ; }
++    @Test public void nodetable_07()    { testNode("'نواف'") ; }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TS_NodeTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TS_NodeTable.java
index 0000000,0000000..62f9388
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TS_NodeTable.java
@@@ -1,0 -1,0 +1,33 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store.nodetable;
++
++import org.junit.runner.RunWith ;
++import org.junit.runners.Suite ;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++    TestNodeTableBase.class
++    , TestNodeTableStoredBase.class
++    , TestNodeTableStored.class
++    , TestNodeTable.class
++})
++public class TS_NodeTable
++{
++
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTable.java
index 0000000,0000000..9b7eda2
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTable.java
@@@ -1,0 -1,0 +1,37 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store.nodetable;
++
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.junit.BuildTestLib ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.setup.StoreParamsBuilder ;
++
++public class TestNodeTable extends AbstractTestNodeTable
++{
++    @Override
++    protected NodeTable createEmptyNodeTable()
++    {
++        StoreParams params = 
++            StoreParamsBuilder.create()
++                .nodeId2NodeCacheSize(10)
++                .node2NodeIdCacheSize(10)
++                .nodeMissCacheSize(10).build() ;
++        return BuildTestLib.makeNodeTable(Location.mem(), "test", params) ;
++    }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableBase.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableBase.java
index 0000000,0000000..d4bf131
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableBase.java
@@@ -1,0 -1,0 +1,39 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store.nodetable;
++
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.junit.BuildTestLib ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.setup.StoreParamsBuilder ;
++
++public class TestNodeTableBase extends AbstractTestNodeTable
++{
++    @Override
++    protected NodeTable createEmptyNodeTable()
++    {
++        StoreParams params = 
++            StoreParamsBuilder.create()
++                .nodeId2NodeCacheSize(-1)
++                .node2NodeIdCacheSize(-1)
++                .nodeMissCacheSize(-1).build() ;
++
++        // No cache, no inlining.
++        return BuildTestLib.makeNodeTableBase(Location.mem(), "test", params) ;
++    }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableStored.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableStored.java
index 0000000,0000000..12063e0
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableStored.java
@@@ -1,0 -1,0 +1,45 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store.nodetable;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.junit.BuildTestLib ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.setup.StoreParamsBuilder ;
++
++
++public class TestNodeTableStored extends AbstractTestNodeTable
++{
++    static String base = ConfigTest.getTestingDir() ;
++    static Location location = Location.create(base+"/nodetable-test") ;
++    
++    @Override
++    protected NodeTable createEmptyNodeTable()
++    {
++        FileOps.ensureDir(location.getDirectoryPath());
++        FileOps.clearDirectory(location.getDirectoryPath());
++        StoreParams params = 
++            StoreParamsBuilder.create()
++                .nodeId2NodeCacheSize(10)
++                .node2NodeIdCacheSize(10)
++                .nodeMissCacheSize(10).build() ;
++        return BuildTestLib.makeNodeTable(location, "test", params) ;
++    }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableStoredBase.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableStoredBase.java
index 0000000,0000000..edbc2d8
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/nodetable/TestNodeTableStoredBase.java
@@@ -1,0 -1,0 +1,46 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store.nodetable;
++
++import org.apache.jena.atlas.lib.FileOps ;
++import org.seaborne.dboe.base.file.Location ;
++import org.seaborne.tdb2.ConfigTest ;
++import org.seaborne.tdb2.junit.BuildTestLib ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.setup.StoreParamsBuilder ;
++
++
++public class TestNodeTableStoredBase extends AbstractTestNodeTable
++{
++    
++    static String base = ConfigTest.getTestingDir() ;
++    static Location location = Location.create(base+"/nodetable-test") ;
++    
++    @Override
++    protected NodeTable createEmptyNodeTable()
++    {
++        FileOps.ensureDir(location.getDirectoryPath());
++        FileOps.clearDirectory(location.getDirectoryPath());
++        StoreParams params = 
++            StoreParamsBuilder.create()
++                .nodeId2NodeCacheSize(-1)
++                .node2NodeIdCacheSize(-1)
++                .nodeMissCacheSize(-1).build() ;
++        return BuildTestLib.makeNodeTableBase(location, "test", params) ;
++    }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/AbstractTestTupleIndex.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/AbstractTestTupleIndex.java
index 0000000,0000000..6a2e138
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/AbstractTestTupleIndex.java
@@@ -1,0 -1,0 +1,264 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store.tupletable;
++
++import static org.apache.jena.atlas.lib.tuple.TupleFactory.tuple ;
++
++import java.util.Iterator ;
++import java.util.Set ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.junit.Test ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.store.tupletable.TupleIndex ;
++import static org.seaborne.tdb2.store.tupletable.NData.*;
++
++/** Test TupleIndexes (general) */
++public abstract class AbstractTestTupleIndex
++{
++    protected abstract TupleIndex create(String description) ;
++    
++    protected static void add(TupleIndex index, NodeId x1, NodeId x2, NodeId x3)
++    {
++        Tuple<NodeId> tuple = tuple(x1, x2, x3) ;
++        index.add(tuple) ;
++    }
++    
++    @Test public void TupleIndex_1()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++    }
++    
++    @Test public void TupleIndexRecordSPO_1()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, n2, n3) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        assertTrue(iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++ 
++    @Test public void TupleIndexRecordSPO_2()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, n2, null) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        assertTrue(iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++    
++    @Test public void TupleIndexRecordSPO_3()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, null, n3) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        assertTrue(iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++    
++    @Test public void TupleIndexRecordSPO_4()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        assertTrue(iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++    
++    @Test public void TupleIndexRecordSPO_5()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n1, n2, n4) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, n2, n3) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++        assertEquals(1, x.size()) ;
++        assertTrue(x.contains(tuple(n1, n2, n3))) ;
++        assertFalse(x.contains(tuple(n1, n2, n4))) ;
++    }
++
++    @Test public void TupleIndexRecordSPO_6()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n1, n2, n4) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, n2, NodeId.NodeIdAny) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++        assertEquals(2, x.size()) ;
++        assertTrue(x.contains(tuple(n1, n2, n3))) ;
++        assertTrue(x.contains(tuple(n1, n2, n4))) ;
++    }
++
++    @Test public void TupleIndexRecordSPO_7()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n1, n2, n4) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++        assertEquals(2, x.size()) ;
++        assertTrue(x.contains(tuple(n1, n2, n3))) ;
++        assertTrue(x.contains(tuple(n1, n2, n4))) ;
++    }
++
++    @Test public void TupleIndexRecordSPO_8()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n2, n3, n4) ;
++
++        {
++            Tuple<NodeId> tuple2 = tuple(n1, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++            Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++            Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++            assertEquals(1, x.size()) ;
++            assertTrue(x.contains(tuple(n1, n2, n3))) ;
++        }
++
++        {
++            Tuple<NodeId> tuple2 = tuple(n2, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++            Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++            Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++            assertEquals(1, x.size()) ;
++            assertTrue(x.contains(tuple(n2, n3, n4))) ;
++        }
++    }
++
++    @Test public void TupleIndexRecordPOS_1()
++    {
++        TupleIndex index = create("POS") ;
++        add(index, n1, n2, n3) ;
++        Tuple<NodeId> tuple2 = tuple(n1, n2, n3) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        assertTrue("Can't find tuple", iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++ 
++    @Test public void TupleIndexRecordPOS_2()
++    {
++        TupleIndex index = create("POS") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(null, n2, null) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        assertTrue("Can't find tuple",iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++    
++
++    @Test public void TupleIndexRecordPOS_3()
++    {
++        TupleIndex index = create("POS") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(null, n2, n3) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        assertTrue("Can't find tuple", iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++
++    @Test public void TupleIndexRecordFindNot_1()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n4, n5, n6) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        assertNotNull(iter) ;
++        assertFalse(iter.hasNext()) ;
++   }
++    
++    @Test public void TupleIndexRecordFindNot_2()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, n5, n6) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        assertFalse(iter.hasNext()) ;
++   }
++
++    @Test public void TupleIndexRecordFindNot_3()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, null, n6) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        assertFalse(iter.hasNext()) ;
++   }
++
++    @Test public void TupleIndexRecordFindNot_4()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n1, n5, n6) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n4, n5, n6) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        assertFalse(iter.hasNext()) ;
++   }
++    
++    @Test public void TupleIndexRecordFindNot_5()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n1, n5, n6) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n2, n5, n6) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        assertFalse(iter.hasNext()) ;
++   }
++
++    @Test public void TupleIndexRecordFindNot_6()
++    {
++        TupleIndex index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n4, n5, n6) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, null, n6) ;
++        Iterator<Tuple<NodeId>> iter = index.find(tuple2) ;
++        assertFalse(iter.hasNext()) ;
++   }
++
++    
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/NData.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/NData.java
index 0000000,0000000..c22451f
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/NData.java
@@@ -1,0 -1,0 +1,37 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store.tupletable;
++
++import org.apache.jena.atlas.lib.BitsLong;
++import org.seaborne.tdb2.store.NodeId;
++import org.seaborne.tdb2.store.NodeIdFactory;
++import org.seaborne.tdb2.store.NodeIdType;
++
++public class NData {
++    public static NodeId n1 = create(1) ;
++    public static NodeId n2 = create(2) ;
++    public static NodeId n3 = create(3) ;
++    public static NodeId n4 = NodeIdFactory.createValue(NodeIdType.XSD_INTEGER, 1);
++    public static NodeId n5 = NodeIdFactory.createValue(NodeIdType.XSD_INTEGER, 2);
++    // -2 as inlined.
++    public static NodeId n6 = NodeIdFactory.createValue(NodeIdType.XSD_INTEGER, BitsLong.clear(-2L, 56, 64));
++    
++    private static NodeId create(long v) {
++        return NodeIdFactory.createPtr(v);
++    }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TS_TupleTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TS_TupleTable.java
index 0000000,0000000..607ffe8
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TS_TupleTable.java
@@@ -1,0 -1,0 +1,31 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store.tupletable;
++
++import org.junit.runner.RunWith;
++import org.junit.runners.Suite;
++
++@RunWith(Suite.class)
++@Suite.SuiteClasses( {
++    TestTupleIndexRecord.class,
++    TestTupleIndexRecordDirect.class,
++    TestTupleTable.class
++} )
++
++public class TS_TupleTable
++{ }

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecord.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecord.java
index 0000000,0000000..ce62f16
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecord.java
@@@ -1,0 -1,0 +1,42 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store.tupletable;
++
++import org.apache.jena.atlas.lib.tuple.TupleMap ;
++import org.seaborne.dboe.base.file.FileSet ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.index.IndexParams ;
++import org.seaborne.dboe.index.RangeIndex ;
++import org.seaborne.tdb2.junit.BuildTestLib ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++
++public class TestTupleIndexRecord extends AbstractTestTupleIndex
++{
++    static RecordFactory factory = new RecordFactory(3*SystemTDB.SizeOfNodeId, 0) ;
++    
++    @Override
++    protected TupleIndexRecord create(String description)
++    {
++        IndexParams indexParams = StoreParams.getDftStoreParams() ; 
++        RangeIndex rIdx = BuildTestLib.buildRangeIndex(FileSet.mem(), factory, indexParams) ;
++        TupleMap tmap = TupleMap.create("SPO", description) ;
++        TupleIndexRecord index = new TupleIndexRecord(3, tmap, description, factory, rIdx) ;
++        return index ;
++    }
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecordDirect.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecordDirect.java
index 0000000,0000000..a48c87b
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleIndexRecordDirect.java
@@@ -1,0 -1,0 +1,314 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store.tupletable;
++
++import static org.seaborne.tdb2.store.tupletable.NData.*;
++import static org.apache.jena.atlas.lib.tuple.TupleFactory.tuple ;
++
++import java.util.Iterator ;
++import java.util.Set ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.apache.jena.atlas.lib.tuple.TupleMap ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.file.FileSet ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.dboe.index.IndexParams ;
++import org.seaborne.dboe.index.RangeIndex ;
++import org.seaborne.tdb2.junit.BuildTestLib ;
++import org.seaborne.tdb2.setup.StoreParams ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++
++public class TestTupleIndexRecordDirect
++{
++    static RecordFactory factory = new RecordFactory(3*SystemTDB.SizeOfNodeId, 0) ;
++    
++    static TupleIndexRecord create(String description)
++    {
++        IndexParams indexParams = StoreParams.getDftStoreParams() ; 
++        RangeIndex rIdx = BuildTestLib.buildRangeIndex(FileSet.mem(), factory, indexParams) ;
++        TupleMap tmap = TupleMap.create("SPO", description) ;
++        TupleIndexRecord index = new TupleIndexRecord(3, tmap, description, factory, rIdx) ;
++        return index ;
++    }
++    
++    static void add(TupleIndexRecord index, NodeId x1, NodeId x2, NodeId x3)
++    {
++        Tuple<NodeId> tuple = tuple(x1, x2, x3) ;
++        index.add(tuple) ;
++    }
++    
++    @Test public void TupleIndexRecord_1()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++    }
++    
++    @Test public void TupleIndexRecordSPO_1()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, n2, n3) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        assertTrue(iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++ 
++    @Test public void TupleIndexRecordSPO_2()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, n2, null) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        assertTrue(iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++    
++    @Test public void TupleIndexRecordSPO_3()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, null, n3) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        assertNull(iter) ;
++        iter = index.findOrPartialScan(tuple2) ;
++        assertTrue(iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++    
++    @Test public void TupleIndexRecordSPO_4()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        assertTrue(iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++    
++    @Test public void TupleIndexRecordSPO_5()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n1, n2, n4) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, n2, n3) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++        assertEquals(1, x.size()) ;
++        assertTrue(x.contains(tuple(n1, n2, n3))) ;
++        assertFalse(x.contains(tuple(n1, n2, n4))) ;
++    }
++
++    @Test public void TupleIndexRecordSPO_6()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n1, n2, n4) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, n2, NodeId.NodeIdAny) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++        assertEquals(2, x.size()) ;
++        assertTrue(x.contains(tuple(n1, n2, n3))) ;
++        assertTrue(x.contains(tuple(n1, n2, n4))) ;
++    }
++
++    @Test public void TupleIndexRecordSPO_7()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n1, n2, n4) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++        assertEquals(2, x.size()) ;
++        assertTrue(x.contains(tuple(n1, n2, n3))) ;
++        assertTrue(x.contains(tuple(n1, n2, n4))) ;
++    }
++
++    @Test public void TupleIndexRecordSPO_8()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n2, n3, n4) ;
++
++        {
++            Tuple<NodeId> tuple2 = tuple(n1, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++            Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++            Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++            assertEquals(1, x.size()) ;
++            assertTrue(x.contains(tuple(n1, n2, n3))) ;
++        }
++
++        {
++            Tuple<NodeId> tuple2 = tuple(n2, NodeId.NodeIdAny, NodeId.NodeIdAny) ;
++            Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++            Set<Tuple<NodeId>> x = Iter.toSet(iter) ;
++            assertEquals(1, x.size()) ;
++            assertTrue(x.contains(tuple(n2, n3, n4))) ;
++        }
++    }
++
++    @Test public void TupleIndexRecordPOS_1()
++    {
++        TupleIndexRecord index = create("POS") ;
++        add(index, n1, n2, n3) ;
++        Tuple<NodeId> tuple2 = tuple(n1, n2, n3) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        assertTrue("Can't find tuple", iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++ 
++    @Test public void TupleIndexRecordPOS_2()
++    {
++        TupleIndexRecord index = create("POS") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(null, n2, null) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        assertTrue("Can't find tuple",iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++    
++
++    @Test public void TupleIndexRecordPOS_3()
++    {
++        TupleIndexRecord index = create("POS") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(null, n2, n3) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        assertTrue("Can't find tuple", iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++
++    @Test public void TupleIndexRecordFindScan_1()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        Tuple<NodeId> tuple2 = tuple(n1, null, n3) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        assertNull(iter) ;
++        iter = index.findOrPartialScan(tuple2) ;
++        assertTrue(iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++    
++    @Test public void TupleIndexRecordFindScan_2()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n1, n2, n4) ;
++        
++        
++        Tuple<NodeId> tuple2 = tuple(null, null, n3) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        assertNull(iter) ;
++        
++        iter = index.findOrPartialScan(tuple2) ;
++        assertNull(iter) ;
++        
++        iter = index.findOrScan(tuple2) ;
++        assertTrue(iter.hasNext()) ;
++        iter.next();
++        assertFalse(iter.hasNext()) ;
++    }
++    
++    @Test public void TupleIndexRecordFindNot_1()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n4, n5, n6) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        assertNotNull(iter) ;
++        assertFalse(iter.hasNext()) ;
++   }
++    
++    @Test public void TupleIndexRecordFindNot_2()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, n5, n6) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        assertFalse(iter.hasNext()) ;
++   }
++
++    @Test public void TupleIndexRecordFindNot_3()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, null, n6) ;
++        Iterator<Tuple<NodeId>> iter = index.findOrPartialScan(tuple2) ;
++        assertFalse(iter.hasNext()) ;
++   }
++
++    @Test public void TupleIndexRecordFindNot_4()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n1, n5, n6) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n4, n5, n6) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        assertFalse(iter.hasNext()) ;
++   }
++    
++    @Test public void TupleIndexRecordFindNot_5()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n1, n5, n6) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n2, n5, n6) ;
++        Iterator<Tuple<NodeId>> iter = index.findByIndex(tuple2) ;
++        assertFalse(iter.hasNext()) ;
++   }
++
++    @Test public void TupleIndexRecordFindNot_6()
++    {
++        TupleIndexRecord index = create("SPO") ;
++        add(index, n1, n2, n3) ;
++        add(index, n4, n5, n6) ;
++        
++        Tuple<NodeId> tuple2 = tuple(n1, null, n6) ;
++        Iterator<Tuple<NodeId>> iter = index.findOrPartialScan(tuple2) ;
++        assertFalse(iter.hasNext()) ;
++   }
++
++    
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleTable.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleTable.java
index 0000000,0000000..4d27266
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/tupletable/TestTupleTable.java
@@@ -1,0 -1,0 +1,151 @@@
++/*
++ *  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.
++ *
++ *  See the NOTICE file distributed with this work for additional
++ *  information regarding copyright ownership.
++ */
++
++package org.seaborne.tdb2.store.tupletable;
++
++import static org.apache.jena.atlas.lib.tuple.TupleFactory.tuple ;
++
++import java.util.Iterator ;
++import java.util.List ;
++
++import org.apache.jena.atlas.iterator.Iter ;
++import static org.junit.Assert.*;
++import org.apache.jena.atlas.lib.tuple.Tuple ;
++import org.junit.Test ;
++import org.seaborne.dboe.base.record.RecordFactory ;
++import org.seaborne.tdb2.store.NodeId ;
++import org.seaborne.tdb2.sys.SystemTDB ;
++import static org.seaborne.tdb2.store.tupletable.NData.*;
++
++public class TestTupleTable
++{
++    static RecordFactory factory = new RecordFactory(3*SystemTDB.SizeOfNodeId, 0) ;
++    
++    static private TupleTable create()
++    {
++        TupleIndex idxSPO = TestTupleIndexRecordDirect.create("SPO") ;
++        TupleIndex idxPOS = TestTupleIndexRecordDirect.create("POS") ;
++        TupleIndex idxOSP = TestTupleIndexRecordDirect.create("OSP") ;
++        TupleIndex x[] = { idxSPO, idxPOS, idxOSP } ;
++        TupleTable table = new TupleTable(3, x) ;
++        return table ;
++    }
++    
++    static private TupleTable create2()
++    {
++        TupleIndex idxSPO = TestTupleIndexRecordDirect.create("SPO") ;
++        TupleIndex x[] = { idxSPO } ;
++        TupleTable table = new TupleTable(3, x) ;
++        return table ;
++    }
++    
++    static void add(TupleTable table, NodeId x1, NodeId x2, NodeId x3)
++    {
++        Tuple<NodeId> tuple = tuple(x1, x2, x3) ;
++        table.add(tuple) ;
++    }
++    
++    @Test public void create1() { create() ; } 
++    
++    @Test public void createFind1()
++    { 
++        TupleTable table = create() ;
++        add(table, n1, n2, n3) ;
++        // Cast removes compile lint warning.
++        Tuple<NodeId> pat = tuple((NodeId)null, null, null) ;
++        Iterator<Tuple<NodeId>> iter = table.find(pat) ;
++        List<Tuple<NodeId>> x = Iter.toList(iter) ;
++        int z = x.size() ;
++        assertEquals(1, z) ;
++        Tuple<NodeId> e1 = x.get(0) ;
++        assertEquals(tuple(n1, n2, n3) , e1) ;
++    }
++    
++    @Test public void createFind2()
++    { 
++        TupleTable table = create() ;
++        add(table, n1, n2, n3) ;
++        add(table, n1, n2, n4) ;
++
++        Tuple<NodeId> pat = tuple(null, n2, null) ;
++        Iterator<Tuple<NodeId>> iter = table.find(pat) ;
++        assertNotNull(iter) ;
++        List<Tuple<NodeId>> x = Iter.toList(iter) ;
++        int z = x.size() ;
++        assertEquals(2, z) ;
++        
++        Tuple<NodeId> e1 = x.get(0) ;
++        Tuple<NodeId> e2 = x.get(1) ;
++        assertEquals(tuple(n1, n2, n3) , e1) ;
++        assertEquals(tuple(n1, n2, n4) , e2) ;
++    }
++    
++    @Test public void createFind3()
++    { 
++        // test scan
++        TupleTable table = create2() ;
++        add(table, n1, n2, n3) ;
++        add(table, n1, n2, n4) ;
++
++        Tuple<NodeId> pat = tuple(n1, null, n3) ;
++        Iterator<Tuple<NodeId>> iter = table.find(pat) ;
++        assertNotNull(iter) ;
++        List<Tuple<NodeId>> x = Iter.toList(iter) ;
++        int z = x.size() ;
++        assertEquals(1, z) ;
++        
++        Tuple<NodeId> e1 = x.get(0) ;
++        assertEquals(tuple(n1, n2, n3) , e1) ;
++    }
++    
++    @Test public void createFind4()
++    { 
++        // test scan
++        TupleTable table = create2() ;
++        add(table, n1, n2, n3) ;
++        add(table, n1, n2, n4) ;
++
++        Tuple<NodeId> pat = tuple(null, null, n3) ;
++        Iterator<Tuple<NodeId>> iter = table.find(pat) ;
++        assertNotNull(iter) ;
++        List<Tuple<NodeId>> x = Iter.toList(iter) ;
++        int z = x.size() ;
++        assertEquals(1, z) ;
++        
++        Tuple<NodeId> e1 = x.get(0) ;
++        assertEquals(tuple(n1, n2, n3) , e1) ;
++    }
++    
++    @Test public void createFind5()
++    { 
++        // test scan
++        TupleTable table = create2() ;
++        add(table, n1, n2, n3) ;
++        add(table, n1, n2, n4) ;
++
++        Tuple<NodeId> pat = tuple(null, NodeId.NodeIdAny, n3) ;
++        Iterator<Tuple<NodeId>> iter = table.find(pat) ;
++        assertNotNull(iter) ;
++        List<Tuple<NodeId>> x = Iter.toList(iter) ;
++        int z = x.size() ;
++        assertEquals(1, z) ;
++        
++        Tuple<NodeId> e1 = x.get(0) ;
++        assertEquals(tuple(n1, n2, n3) , e1) ;
++    }
++
++}

http://git-wip-us.apache.org/repos/asf/jena/blob/d9da3592/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/value/TestDoubleNode62.java
----------------------------------------------------------------------
diff --cc jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/value/TestDoubleNode62.java
index 0000000,0000000..112bd52
new file mode 100644
--- /dev/null
+++ b/jena-db/tdb2/src/test/java/org/seaborne/tdb2/store/value/TestDoubleNode62.java
@@@ -1,0 -1,0 +1,123 @@@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements.  See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership.  The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License.  You may obtain a copy of the License at
++ *
++ *     http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++package org.seaborne.tdb2.store.value;
++
++import org.apache.jena.atlas.lib.BitsLong;
++import org.junit.Test;
++import org.seaborne.tdb2.store.value.DoubleNode62;
++
++import static org.junit.Assert.*;
++
++public class TestDoubleNode62 {
++    @Test public void double_01() { testRoundTripDouble(1d); }
++    @Test public void double_02() { testRoundTripDouble(-1d); }
++    @Test public void double_03() { testRoundTripDouble(-1111111111e50d); }
++    @Test public void double_04() { testRoundTripDouble(1111111111e50d); }
++
++    @Test public void double_05() { testNoEncoding(1e300); }
++    @Test public void double_06() { testNoEncoding(1e100); }
++    @Test public void double_07() { testNoEncoding(1e78); }
++    @Test public void double_08() { testNoEncoding(2e77); }
++    @Test public void double_09() { testRoundTripDouble(1e77); }
++    
++    @Test public void double_10() { testNoEncoding(3e-300); }
++    @Test public void double_11() { testNoEncoding(3e-100); }
++    @Test public void double_12() { testNoEncoding(3e-77); }
++    @Test public void double_13() { testRoundTripDouble(3.5e-77); }
++    @Test public void double_14() { testRoundTripDouble(4e-77); }
++    @Test public void double_15() { testRoundTripDouble(1e-76); }
++    @Test public void double_16() { testRoundTripDouble(1e-75); }
++    
++    @Test public void double_20() { testRoundTripDouble(Double.POSITIVE_INFINITY); }
++    @Test public void double_21() { testRoundTripDouble(Double.NEGATIVE_INFINITY); }
++    @Test public void double_22() { testRoundTripDouble(Double.NaN); }
++    @Test public void double_23() { testNoEncoding(Double.MAX_VALUE); }
++    @Test public void double_24() { testNoEncoding(Double.MIN_NORMAL); }
++    @Test public void double_25() { testNoEncoding(Double.MIN_VALUE); }
++
++    @Test public void double_30() { testRoundTripDouble(DoubleNode62.POSITIVE_INFINITY); }
++    @Test public void double_31() { testRoundTripDouble(DoubleNode62.NEGATIVE_INFINITY); }
++    @Test public void double_32() { testRoundTripDouble(DoubleNode62.NaN); }
++    @Test public void double_33() { testNoEncoding(DoubleNode62.MAX_VALUE); }
++    @Test public void double_34() { testNoEncoding(DoubleNode62.MIN_NORMAL); }
++    @Test public void double_35() { testNoEncoding(DoubleNode62.MIN_VALUE); }
++
++    @Test public void double_40() { sameValue(DoubleNode62.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); }
++    @Test public void double_41() { sameValue(DoubleNode62.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY); }
++    @Test public void double_42() { sameValue(DoubleNode62.NaN, Double.NaN); }
++
++    @Test public void double_50() { testConst(DoubleNode62.POSITIVE_INFINITY_BITS, 0x1ff0000000000000L); }
++    @Test public void double_51() { testConst(DoubleNode62.NEGATIVE_INFINITY_BITS, 0x3ff0000000000000L); }
++    @Test public void double_52() { testConst(DoubleNode62.NaN_BITS, 0x1ff8000000000000L); }
++    @Test public void double_53() { testConst(DoubleNode62.MAX_VALUE_BITS,  0x3fefffffffffffffL); }
++    @Test public void double_54() { testConst(DoubleNode62.MIN_NORMAL_BITS, 0x0010000000000000L); }
++    @Test public void double_55() { testConst(DoubleNode62.MIN_VALUE_BITS,  0x01L); }
++    
++    private void sameValue(double d1, double d2) {
++        // Not d1 == d2 - NaN != NaN 
++        assertEquals(Double.valueOf(d1), Double.valueOf(d2));  
++    }
++    
++    private static void testConst(long x, long expected) {
++        //print(expected);
++        //print(x);
++        assertEquals(expected, x);
++        double d = DoubleNode62.unpack(x);
++        long z = DoubleNode62.pack(d);
++        assertEquals(expected, z);
++    }
++    
++    private void testNoEncoding(double d) {
++        testRoundTripDouble(d, false); 
++    }
++
++    private static void testRoundTripDouble(double d) {
++        testRoundTripDouble(d, true); 
++    }
++    
++    private static void testRoundTripDouble(double d, boolean valid) {
++        //System.out.printf("Double: %.2e\n", d);
++        long x0 = Double.doubleToRawLongBits(d);
++        //print(x0);
++        long x = DoubleNode62.pack(d);
++        //print(x);
++        if ( x == DoubleNode62.NO_ENCODING ) {
++            if ( valid )
++                fail("Expect no encoding");
++            
++            //System.out.println("No encoding");
++            //System.out.println();
++            return;
++        }
++        
++        double d2 = DoubleNode62.unpack(x);
++        
++        Double double1 = d ;
++        Double double2 = d2 ;
++        assertEquals(double1, double2);
++    }
++
++    private static void print(long x) {
++        long z[] = new long[4];
++        for ( int i = 0 ; i < 4 ; i++ ) {
++             z[3-i] = BitsLong.unpack(x, i*16, (i+1)*16) ;
++        }
++        System.out.printf("0x%04X %04X %04X %04X\n", z[0], z[1], z[2], z[3]);
++    }
++}