/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is the Kowari Metadata Store.
*
* The Initial Developer of the Original Code is Plugged In Software Pty
* Ltd (http://www.pisoftware.com, mailto:info@pisoftware.com). Portions
* created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
* Plugged In Software Pty Ltd. All Rights Reserved.
*
* Contributor(s): N/A.
*
* [NOTE: The text of this Exhibit A may differ slightly from the text
* of the notices in the Source Code files of the Original Code. You
* should use the text of this Exhibit A rather than the text found in the
* Original Code Source Code for Your Modifications.]
*
*/
package org.mulgara.store.bdb;
// Third party packages
import junit.framework.*;
import java.io.*;
// Java 2 standard packages
import java.util.*;
import org.apache.log4j.Logger;
// Locally written packages.
import org.mulgara.query.Variable;
import org.mulgara.store.tuples.DefaultRowComparator;
import org.mulgara.store.tuples.LiteralTuples;
import org.mulgara.store.tuples.RowComparator;
/**
* Test cases for DbTuples.
*
* @created 2003-02-04
*
* @author Paula Gearon
*
* @version $Revision: 1.9 $
*
* @modified $Date: 2005/01/05 04:59:12 $
*
* @maintenanceAuthor $Author: newmana $
*
* @company <A href="mailto:info@PIsoftware.com">Plugged In Software</A>
*
* @copyright ©2004 <a href="http://www.pisoftware.com/">Plugged In
* Software Pty Ltd</a>
*
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
public class DbTuplesTest extends TestCase {
// Larger than this and in memory structures used by the tests fail with OOM
// private final static int LOAD_SIZE = 262142;
private final static int LOAD_SIZE = 1000000;
private final static int ODD_LOAD_SIZE = 200000;
private final static int BF_SMALL_LOAD_SIZE = 10;
private final static int BF_LARGE_LOAD_SIZE = 100;
private final static Logger logger = Logger.getLogger(DbTuplesTest.class);
private final static int WIDTH = 3;
private DbTuples dbTuples;
private RowComparator rowComparator;
private final static Comparator<long[]> longSingletonArrayComparator = new Comparator<long[]>() {
public int compare(long[] a1, long[] a2) {
return a1[0] == a2[0] ? 0 : (a1[0] < a2[0] ? -1 : +1);
}
};
/**
* Named constructor.
*
* @param name The name of the test.
*/
public DbTuplesTest(String name) {
super(name);
}
/**
* Hook for test runner to obtain a test suite from.
*
* @return The test suite to run.
*/
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(new DbTuplesTest("testCreate"));
suite.addTest(new DbTuplesTest("testSort"));
suite.addTest(new DbTuplesTest("testOddLoad"));
suite.addTest(new DbTuplesTest("testLoadSort"));
suite.addTest(new DbTuplesTest("testEmpty"));
suite.addTest(new DbTuplesTest("testLargeOrdered"));
suite.addTest(new DbTuplesTest("testCloneAndClose"));
// determine why these do not work
// suite.addTest(new DbTuplesTest("testPositioning"));
// suite.addTest(new DbTuplesTest("testSmallBeforeFirst"));
// suite.addTest(new DbTuplesTest("testLargeBeforeFirst"));
return suite;
}
/**
* Default test runner.
*
* @param args The command line arguments
*/
public static void main(String[] args) {
junit.textui.TestRunner.run(suite());
}
/**
* Creates a new file required to do the testing.
*
* @throws Exception EXCEPTION TO DO
*/
public void setUp() throws Exception {
boolean exceptionOccurred = true;
try {
rowComparator = DefaultRowComparator.getInstance();
exceptionOccurred = false;
} finally {
if (exceptionOccurred) {
tearDown();
}
}
}
/**
* Closes the file used for testing.
*
* @throws Exception EXCEPTION TO DO
*/
public void tearDown() throws Exception {
if (dbTuples != null) {
dbTuples.close();
dbTuples = null;
}
}
/**
* Test creation based on a 6 element set.
*
* @throws Exception EXCEPTION TO DO
*/
public void testCreate() throws Exception {
LiteralTuples tt = new LiteralTuples(new String[] { "test" });
tt.appendTuple(new long[] { 1 });
tt.appendTuple(new long[] { 2 });
tt.appendTuple(new long[] { 3 });
tt.appendTuple(new long[] { 4 });
tt.appendTuple(new long[] { 5 });
tt.appendTuple(new long[] { 6 });
dbTuples = new DbTuples(tt, rowComparator);
dbTuples.beforeFirst();
// check that the order is as expected
long row = 1;
while (dbTuples.next()) {
assertEquals(row++, dbTuples.getColumnValue(0));
}
// check for the correct number of elements in dbTuples
assertTrue(row == 7);
}
/**
* Test sorting
*
* @throws Exception EXCEPTION TO DO
*/
public void testSort() throws Exception {
LiteralTuples tt = new LiteralTuples(new String[] { "test" });
tt.appendTuple(new long[] { 6 });
tt.appendTuple(new long[] { 5 });
tt.appendTuple(new long[] { 4 });
tt.appendTuple(new long[] { 3 });
tt.appendTuple(new long[] { 2 });
tt.appendTuple(new long[] { 1 });
dbTuples = new DbTuples(tt, rowComparator);
dbTuples.beforeFirst();
// check that the order is as expected
long row = 1;
while (dbTuples.next()) {
assertEquals(row++, dbTuples.getColumnValue(0));
}
// check for the correct number of elements in dbTuples
assertTrue(row == 7);
}
/**
* Test cloneing DbTuples and closing original copy.
*
* @throws Exception EXCEPTION TO DO
*/
public void testCloneAndClose() throws Exception {
LiteralTuples tt = new LiteralTuples(new String[] { "test" });
tt.appendTuple(new long[] { 6 });
tt.appendTuple(new long[] { 5 });
tt.appendTuple(new long[] { 4 });
tt.appendTuple(new long[] { 3 });
tt.appendTuple(new long[] { 2 });
tt.appendTuple(new long[] { 1 });
DbTuples origTuples = new DbTuples(tt, rowComparator);
dbTuples = (DbTuples)origTuples.clone();
origTuples.close();
dbTuples.beforeFirst();
// check that the order is as expected
long row = 1;
while (dbTuples.next()) {
assertEquals(row++, dbTuples.getColumnValue(0));
}
// check for the correct number of elements in dbTuples
assertTrue(row == 7);
}
/**
* Load test the sorting
*
* @throws Throwable EXCEPTION TO DO
*/
public void testLoadSort() throws Throwable {
Random r = new Random(42); // use a constant seed
long[] v = new long[] { r.nextLong() & 0xFFFFFFFFL };
LiteralTuples tt = new LiteralTuples(new String[] { "test" });
tt.appendTuple(v);
ArrayList<long[]> values = new ArrayList<long[]>();
values.add(v);
// iterate over a large enough range to guarantee several blocks
for (int i = 0; i < LOAD_SIZE; i++) {
v = new long[] { r.nextLong() & 0xFFFFFFFFL };
if (v[0] == 0) {
v[0]++;
}
values.add(v);
tt.appendTuple(v);
}
Collections.sort(values, longSingletonArrayComparator);
// logger.info("LoadSort: Creating DbTuples");
dbTuples = new DbTuples(tt, rowComparator);
// logger.info("LoadSort: BeforeFirst");
dbTuples.beforeFirst();
// logger.info("LoadSort: Checking Order");
// check that the order is as expected
Iterator<long[]> it = values.iterator();
int i = 0;
try {
while (it.hasNext()) {
assertEquals("On iteration " + i, dbTuples.next(), true);
v = it.next();
i++;
// if (i % 10000 == 0) {
// logger.info("Checked " + i + " tuples");
// }
assertEquals("On iteration " + i, v[0], dbTuples.getColumnValue(0));
}
} catch (Throwable e) {
// for debugging:
// dumpFile(dbTuples);
throw e;
}
// logger.info("LoadSort: Finished order check");
// check that there aren't any extraneous values
assertTrue(!dbTuples.next());
// logger.info("LoadSort: Finished test");
}
/**
* Load test odd sized tuples
*
* @throws Throwable EXCEPTION TO DO
*/
public void testOddLoad() throws Throwable {
Variable[] vars = new Variable[WIDTH];
for (int c = 0; c < WIDTH; c++) {
vars[c] = new Variable("test" + (c + 1));
}
// use a constant seed
Random r = new Random(42);
LiteralTuples tt = new LiteralTuples(vars);
long[] v = new long[WIDTH];
// iterate over a large enough range to guarantee several blocks
for (int i = 0; i < ODD_LOAD_SIZE; i++) {
for (int c = 0; c < WIDTH; c++) {
v[c] = r.nextLong() & 0x0000FFFFL;
if (v[c] == 0) {
v[c]++;
}
}
tt.appendTuple(v);
}
dbTuples = new DbTuples(tt, rowComparator);
dbTuples.beforeFirst();
// check that the order is as expected
long[] tuple = new long[WIDTH];
long[] lastTuple = new long[WIDTH];
for (int c = 0; c < WIDTH; c++) {
lastTuple[c] = 0;
}
int i = 0;
try {
while (dbTuples.next()) {
for (int c = 0; c < WIDTH; c++) {
tuple[c] = dbTuples.getColumnValue(c);
}
for (int c = 0; c < WIDTH; c++) {
if (tuple[c] < lastTuple[c]) {
logger.error("Error tuple[" + tuple[0] + "," + tuple[1] + "," +
tuple[2] + "] < lastTuple[" + lastTuple[0] + "," + lastTuple[1] +
"," + lastTuple[2] + "]");
}
assertTrue(tuple[c] >= lastTuple[c]);
if (tuple[c] != lastTuple[c]) {
break;
}
}
for (int c = 0; c < WIDTH; c++) {
lastTuple[c] = tuple[c];
}
i++;
}
} catch (Throwable e) {
// for debugging:
// dumpFile(dbTuples);
throw e;
}
// check that there aren't any extraneous values
// logger.warn("i = " + i + ", LOAD_SIZE = " + ODD_LOAD_SIZE);
assertTrue(i == ODD_LOAD_SIZE);
}
/**
* Test adding an empty tuple
*
* @throws Exception EXCEPTION TO DO
*/
public void testEmpty() throws Exception {
LiteralTuples tt = new LiteralTuples(new Variable[] {});
dbTuples = new DbTuples(tt, rowComparator);
dbTuples.beforeFirst();
// check that the order is as expected
assertTrue(!dbTuples.next());
}
/**
* Test the {@link DbTuples#beforeFirst(long[], int)} and {@link
* DbTuples#next} methods.
*
* @throws Exception EXCEPTION TO DO
*/
public void testPositioning() throws Exception {
LiteralTuples tt = new LiteralTuples(new String[] { "x", "y" });
tt.appendTuple(new long[] { 1, 2 });
tt.appendTuple(new long[] { 3, 4 });
tt.appendTuple(new long[] { 5, 6 });
tt.appendTuple(new long[] { 7, 8 });
dbTuples = new DbTuples(tt, rowComparator);
dbTuples.beforeFirst(new long[] {7, 8} , 0);
assertTrue(dbTuples.next());
assertEquals(7, dbTuples.getColumnValue(0));
assertEquals(8, dbTuples.getColumnValue(1));
assertTrue(!dbTuples.next());
dbTuples.beforeFirst();
assertTrue(dbTuples.next());
assertEquals(1, dbTuples.getColumnValue(0));
assertEquals(2, dbTuples.getColumnValue(1));
dbTuples.beforeFirst(new long[] {7, 8} , 0);
assertTrue(dbTuples.next());
assertEquals(7, dbTuples.getColumnValue(0));
assertEquals(8, dbTuples.getColumnValue(1));
assertTrue(!dbTuples.next());
dbTuples.beforeFirst(new long[] {1, 2} , 0);
assertTrue(dbTuples.next());
assertEquals(1, dbTuples.getColumnValue(0));
assertEquals(2, dbTuples.getColumnValue(1));
assertTrue(!dbTuples.next());
dbTuples.beforeFirst(new long[] {2} , 0);
assertTrue(!dbTuples.next());
dbTuples.beforeFirst(new long[] {3} , 0);
assertTrue(dbTuples.next());
assertEquals(3, dbTuples.getColumnValue(0));
assertEquals(4, dbTuples.getColumnValue(1));
assertTrue(!dbTuples.next());
dbTuples.close();
dbTuples = null;
}
public void testLargeOrdered() throws Throwable {
LiteralTuples tt = new LiteralTuples(new String[] { "test" });
ArrayList<long[]> values = new ArrayList<long[]>();
long count = 0;
// iterate over a large enough range to guarantee several blocks
for (int i = 0; i < LOAD_SIZE; i++) {
long[] v = new long[] { count++ };
v[0] = count++;
values.add(v);
tt.appendTuple(v);
}
Collections.sort(values, longSingletonArrayComparator);
dbTuples = new DbTuples(tt, rowComparator);
dbTuples.beforeFirst();
// check that the order is as expected
Iterator<long[]> it = values.iterator();
int i = 0;
try {
while (it.hasNext()) {
assertTrue(dbTuples.next());
long[] v = it.next();
i++;
assertEquals("On iteration " + i, v[0], dbTuples.getColumnValue(0));
}
} catch (Throwable e) {
// for debugging:
// dumpFile(dbTuples);
throw e;
}
// check that there aren't any extraneous values
assertTrue(!dbTuples.next());
}
public void testSmallBeforeFirst() throws Throwable {
logger.warn("testSmallBeforeFirst");
LiteralTuples tt = new LiteralTuples(new String[] { "i", "j", "k" });
logger.warn("testSmallBeforeFirst: checkpoint 1");
// iterate over a large enough range to guarantee several blocks
for (int i = (BF_SMALL_LOAD_SIZE * 2) - 1; i > 0; i -= 2) {
for (int j = (BF_SMALL_LOAD_SIZE * 2) - 1; j > 0; j -= 2) {
for (int k = (BF_SMALL_LOAD_SIZE * 2) - 1; k > 0; k -= 2) {
long[] v = new long[] { i, j, k };
tt.appendTuple(v);
}
}
}
logger.warn("testSmallBeforeFirst: checkpoint 2");
dbTuples = new DbTuples(tt, rowComparator);
logger.warn("testSmallBeforeFirst: checkpoint 3");
dbTuples.beforeFirst();
// check that the order is as expected
logger.warn("testSmallBeforeFirst: checkpoint 4");
try {
long count = 0;
for (int i = 1; i < BF_SMALL_LOAD_SIZE * 2; i += 2) {
for (int j = 1; j < BF_SMALL_LOAD_SIZE * 2; j += 2) {
for (int k = 1; k < BF_SMALL_LOAD_SIZE * 2; k += 2) {
count++;
assertTrue(dbTuples.next());
assertEquals("On iteration " + count, i, dbTuples.getColumnValue(0));
assertEquals("On iteration " + count, j, dbTuples.getColumnValue(1));
assertEquals("On iteration " + count, k, dbTuples.getColumnValue(2));
}
}
}
// check that there aren't any extraneous values
assertTrue(!dbTuples.next());
} catch (Throwable e) {
// for debugging:
// dumpFile(dbTuples);
throw e;
}
logger.warn("testSmallBeforeFirst: checkpoint 5");
dbTuples.beforeFirst(new long[] { 3, 5 }, 0);
logger.warn("testSmallBeforeFirst: checkpoint 6");
// check that the order is as expected
try {
long count = 0;
int i = 3;
int j = 5;
for (int k = 1; k < BF_SMALL_LOAD_SIZE * 2; k += 2) {
count++;
assertTrue(dbTuples.next());
assertEquals("On iteration " + count, i, dbTuples.getColumnValue(0));
assertEquals("On iteration " + count, j, dbTuples.getColumnValue(1));
assertEquals("On iteration " + count, k, dbTuples.getColumnValue(2));
}
// check that there aren't any extraneous values
assertTrue(!dbTuples.next());
} catch (Throwable e) {
// for debugging:
// dumpFile(dbTuples);
throw e;
}
logger.warn("testSmallBeforeFirst: checkpoint 7");
dbTuples.beforeFirst(new long[] { 3, 4 }, 0);
logger.warn("testSmallBeforeFirst: checkpoint 8");
assertFalse(dbTuples.next());
}
public void testLargeBeforeFirst() throws Throwable {
logger.info("testLargeBeforeFirst");
LiteralTuples tt = new LiteralTuples(new String[] { "i", "j", "k" });
// iterate over a large enough range to guarantee several blocks
for (int i = (BF_LARGE_LOAD_SIZE * 2) - 1; i > 0; i -= 2) {
for (int j = (BF_LARGE_LOAD_SIZE * 2) - 1; j > 0; j -= 2) {
for (int k = (BF_LARGE_LOAD_SIZE * 2) - 1; k > 0; k -= 2) {
long[] v = new long[] { i, j, k };
tt.appendTuple(v);
}
}
}
dbTuples = new DbTuples(tt, rowComparator);
dbTuples.beforeFirst();
// check that the order is as expected
try {
long count = 0;
for (int i = 1; i < BF_LARGE_LOAD_SIZE * 2; i += 2) {
for (int j = 1; j < BF_LARGE_LOAD_SIZE * 2; j += 2) {
for (int k = 1; k < BF_LARGE_LOAD_SIZE * 2; k += 2) {
count++;
assertTrue(dbTuples.next());
assertEquals("On iteration " + count, i, dbTuples.getColumnValue(0));
assertEquals("On iteration " + count, j, dbTuples.getColumnValue(1));
assertEquals("On iteration " + count, k, dbTuples.getColumnValue(2));
}
}
}
// check that there aren't any extraneous values
assertTrue(!dbTuples.next());
} catch (Throwable e) {
// for debugging:
// dumpFile(dbTuples);
throw e;
}
dbTuples.beforeFirst(new long[] { 1, 133 }, 0);
// check that the order is as expected
try {
long count = 0;
int i = 1;
int j = 133;
for (int k = 1; k < BF_LARGE_LOAD_SIZE * 2; k += 2) {
count++;
if(!dbTuples.next()) {
logger.error("On iteration " + count + " dbTuples failed .next()");
assertTrue(false);
}
assertEquals("i On iteration " + count, i, dbTuples.getColumnValue(0));
assertEquals("j On iteration " + count, j, dbTuples.getColumnValue(1));
assertEquals("k On iteration " + count, k, dbTuples.getColumnValue(2));
}
// check that there aren't any extraneous values
assertTrue(!dbTuples.next());
} catch (Throwable e) {
// for debugging:
// dumpFile(dbTuples);
throw e;
}
dbTuples.beforeFirst(new long[] { 3, 4 }, 0);
assertFalse(dbTuples.next());
}
/**
* METHOD TO DO
*
* @param ft PARAMETER TO DO
* @throws Exception EXCEPTION TO DO
*/
@SuppressWarnings("unused")
private void dumpFile(DbTuples ft) throws Exception {
PrintStream ps = new PrintStream(new FileOutputStream("/tmp/random.dump"));
try {
ft.beforeFirst();
while (ft.next()) {
ps.println(ft.getColumnValue(0));
}
} finally {
ps.close();
}
}
}