Import BSDDB 4.7.25 (as of svn r89086)

This commit is contained in:
Zachary Ware
2017-09-04 13:40:25 -05:00
parent 4b29e0458f
commit 8f590873d0
4781 changed files with 2241032 additions and 6 deletions

32
test/scr024/Makefile Normal file
View File

@@ -0,0 +1,32 @@
TESTCLASSES=\
./src/com/sleepycat/bind/serial/test/*.java\
./src/com/sleepycat/bind/test/*.java\
./src/com/sleepycat/bind/tuple/test/*.java\
./src/com/sleepycat/collections/test/*.java\
./src/com/sleepycat/collections/test/serial/*.java\
./src/com/sleepycat/util/test/*.java
TESTSERIALPATH=com/sleepycat/collections/test/serial/TestSerial
all: dbtest.jar
dbtest.jar: classesdir
# Compile the tests and build the test jar
javac -classpath ${DB_JAR}:${REQUIRED_JARS} \
-d ./classes ${TESTCLASSES}
jar cf ./dbtest.jar -C ./classes ./com/sleepycat
# Build the original version of TestSerial in the testserial directory
mkdir -p "testserial/${TESTSERIALPATH}"
cp "./src/${TESTSERIALPATH}.java.original" \
"./testserial/${TESTSERIALPATH}.java"
javac -classpath ${DB_JAR}:${REQUIRED_JARS} \
-d ./testserial "testserial/${TESTSERIALPATH}.java"
classesdir:
[ -d ./classes ] || (mkdir ./classes)
clean:
[ -d ./classes ] && rm -rf ./classes
[ -f ./dbtest.jar ] && rm ./dbtest.jar
[ -d ./testserial ] && rm -rf ./testserial

16
test/scr024/README Normal file
View File

@@ -0,0 +1,16 @@
This directory contains a set of tests written in Java run by JUnit. To be
able to run them you must first set the following environment variables.
example sh:
JUNIT_JAR="$HOME/tools/junit3.8.1/junit.jar"
export JUNIT_JAR
XMLAPI_JAR="$HOME/tools/ant/lib/xml-apis.jar"
export XMLAPI_JAR
XMLIMPL_JAR="$HOME/tools/ant/lib/xercesImpl.jar"
export XMLIMPL_JAR
example csh:
setenv JUNIT_JAR $HOME/tools/junit3.8.1/junit.jar
setenv XMLAPI_JAR $HOME/tools/ant/lib/xml-apis.jar
setenv XMLIMPL_JAR $HOME/tools/ant/lib/xercesImpl.jar

67
test/scr024/chk.bdb Normal file
View File

@@ -0,0 +1,67 @@
#!/bin/sh -
#
# $Id: chk.bdb,v 12.1 2006/09/12 00:37:26 alexg Exp $
#
# Run the collections/bind test suite.
# NOTES:
# This test requires one JAR not included with the Berkeley DB
# distribution: JUnit (junit.jar) I've been using the 8/31/2002 version
# of JUnit. You can download this JAR from http://jakarta.apache.org/
#
# JUNIT_JAR=/Users/gburd/Unix/opt/junit/junit.jar
[ "x$JUNIT_JAR" = "x" ] && {
echo 'FAIL: unset environment variable JUNIT_JAR for junit.jar.'
exit 1
}
[ -f $JUNIT_JAR ] || {
echo 'FAIL: JUNIT_JAR not a valid path to the junit.jar.'
exit 1
}
d=..
REQUIRED_JARS=$JUNIT_JAR
DB_JAR=$d/db.jar
DB_LIB_DIR=$d/.libs
export DB_JAR
export REQUIRED_JARS
# Build the tests.
make clean
[ -f ./dbtest.jar ] || (make dbtest.jar) || {
echo 'FAIL: unable to find or build dbtest.jar'
exit 1
}
# Perform initialization needed before StoredClassCatalogTest is run in
# the tests below. The testserial directory must be first in the classpath.
c="com.sleepycat.collections.test.serial.StoredClassCatalogTestInit"
echo "Running: $c"
if java -Djava.library.path=$DB_LIB_DIR \
-cp testserial:$REQUIRED_JARS:$DB_JAR:./dbtest.jar $c ; then
:
else
echo "FAIL: test program failed"
exit 1
fi
# Run the tests.
for f in `find classes -name "*Test.class"`; do
c=`echo "$f" | sed -e 's/classes\///' -e 's/\.class//' -e 's/\//./g'`
echo "Running: $c"
if java -Djava.library.path=$DB_LIB_DIR \
-cp $REQUIRED_JARS:$DB_JAR:./dbtest.jar $c ; then
:
else
echo "FAIL: test program failed"
exit 1
fi
done
exit 0

View File

@@ -0,0 +1,25 @@
The Ant build.xml file in this directory compiles all db Java sources (except
examples), runs the test suite using Clover to instrument the sources, and then
generates the Clover coverage reports.
You must place clover.jar in your Ant lib directory as well as placing
clover.jar and velocity.jar in this directory. (Using a classpathref in the
Ant javac task doesn't seem to work.)
$ cp <YOUR-CLOVER-INSTALL>/clover.jar .
$ cp <YOUR-CLOVER-INSTALL>/velocity.jar .
$ cp clover.jar <YOUR-ANT-DIRECTORY>/lib
$ ant all
'ant all' will delete all output files, compile and run the tests, and then
generate the reports.
'ant' will compile sources that need compiling and run the tests to collect
coverage information.
'ant report' will generate the reports against the current coverage database.
The build.xml file works when run from db/test/scr024/coverage but it should
also work when run from a build directory copied by the TCL test harness, e.g.,
db/build_unix/TESTDIR/coverage.

View File

@@ -0,0 +1,233 @@
<!-- $Id: build.xml 63573 2008-05-23 21:43:21Z trent.nelson $ -->
<project name="clover" default="build" basedir=".">
<property name="db" location="../../.."/>
<property name="src" location="${db}/java/src"/>
<property name="test.src" location="${db}/test/scr024/src"/>
<property name="examples.src" location="${db}/examples_java/src"/>
<property name="testserialdir" value="testserial"/>
<property name="clover.initstring" location="reports/clover.db"/>
<property name="clover.excludes" value="**/test/** collections/** db/** com/sleepycat/db/**"/>
<!--
<property name="build.compiler"
value="org.apache.tools.ant.taskdefs.CloverCompilerAdapter"/>
-->
<target name="all" depends="clean,test,report"/>
<target name="clean">
<delete dir="classes"/>
<delete dir="tmp"/>
<delete dir="reports"/>
</target>
<target name="init">
<mkdir dir="classes"/>
<mkdir dir="tmp"/>
<mkdir dir="reports"/>
</target>
<path id="clover.classpath">
<pathelement location="clover.jar"/>
<pathelement location="velocity.jar"/>
</path>
<path id="classpath">
<pathelement location="classes"/>
<path refid="clover.classpath"/>
</path>
<target name="build" depends="init">
<javac destdir="classes" debug="on" source="1.5" target="1.5">
<src path="${src}"/>
<src path="${test.src}"/>
<src path="${examples.src}"/>
<exclude name="com/sleepycat/**/release/**"/>
<exclude name="com/sleepycat/xa/**"/>
</javac>
<!-- Compile original version of TestSerial.java.original. -->
<property name="testserialpath"
value="com/sleepycat/collections/test/serial/TestSerial"/>
<copy file="${test.src}/${testserialpath}.java.original"
tofile="${testserialdir}/${testserialpath}.java"/>
<javac destdir="${testserialdir}" debug="on" source="1.5" target="1.5"
includeAntRuntime="true" srcdir="${testserialdir}">
<include name="${testserialpath}.java"/>
</javac>
<!-- Compile original version of EvolveClasses. -->
<copy file=
"${test.src}/com/sleepycat/persist/test/EvolveClasses.java.original"
tofile=
"testevolvedir/com/sleepycat/persist/test/EvolveClasses.java"/>
<copy file=
"${test.src}/com/sleepycat/persist/test/EvolveCase.java"
tofile=
"testevolvedir/com/sleepycat/persist/test/EvolveCase.java"/>
<copy file=
"${test.src}/com/sleepycat/persist/test/PersistTestUtils.java"
tofile=
"testevolvedir/com/sleepycat/persist/test/PersistTestUtils.java"/>
<javac debug="on" source="1.5" target="1.5" classpath="classes">
<src path="testevolvedir"/>
</javac>
</target>
<target name="test" depends="build">
<!-- Determine which tests to run. -->
<condition property="dotestserial">
<or>
<not><isset property="testcase"/></not>
<equals arg1="${testcase}" arg2=
"com.sleepycat.collections.test.serial.StoredClassCatalogTest"/>
</or>
</condition>
<condition property="dotestevolve">
<or>
<not><isset property="testcase"/></not>
<equals arg1="${testcase}"
arg2="com.sleepycat.persist.test.EvolveTest"/>
</or>
</condition>
<!-- Performs initialization needed before StoredClassCatalogTest. -->
<junit fork="yes" dir="." printsummary="on" haltonfailure="on"
showoutput="on">
<jvmarg value="-ea"/>
<classpath path="${testserialdir}"/> <!-- Must be first -->
<classpath refid="classpath"/>
<sysproperty key="testdestdir" value="./tmp"/>
<sysproperty key="longtest" value="${longtest}"/>
<formatter type="plain" usefile="false"/>
<formatter type="xml"/>
<test name=
"com.sleepycat.collections.test.serial.StoredClassCatalogTestInit"
todir="reports" if="dotestserial"/>
</junit>
<!-- Performs initialization needed before persist EvolveTest. -->
<junit fork="yes" dir="." printsummary="on" haltonfailure="on"
showoutput="on">
<jvmarg value="-ea"/>
<classpath path="testevolvedir"/>
<classpath refid="classpath"/>
<sysproperty key="testdestdir" value="./tmp"/>
<sysproperty key="longtest" value="${longtest}"/>
<formatter type="plain" usefile="false"/>
<formatter type="xml"/>
<test name="com.sleepycat.persist.test.EvolveTestInit"
todir="reports" if="dotestevolve"/>
</junit>
<!-- Performs testcase if set, or batch tests. -->
<junit fork="yes" dir="." printsummary="on" haltonfailure="on"
showoutput="on">
<jvmarg value="-ea"/>
<classpath refid="classpath"/>
<sysproperty key="testdestdir" value="./tmp"/>
<sysproperty key="longtest" value="${longtest}"/>
<formatter type="plain" usefile="false"/>
<formatter type="xml"/>
<test name="${testcase}" todir="reports" if="testcase"/>
<batchtest todir="reports" unless="testcase">
<fileset dir="classes" includes="**/*Test.class"/>
</batchtest>
</junit>
</target>
<target name="testevolve" depends="build">
</target>
<target name="examples" depends="build">
<echo message="=== HelloDatabaseWorld ==="/>
<java dir="." fork="yes" classpathref="classpath"
classname="collections.hello.HelloDatabaseWorld"/>
<echo message=""/>
<antcall target="one_shipment_example">
<param name="param_name" value="basic"/>
</antcall>
<antcall target="one_shipment_example">
<param name="param_name" value="index"/>
</antcall>
<antcall target="one_shipment_example">
<param name="param_name" value="entity"/>
</antcall>
<antcall target="one_shipment_example">
<param name="param_name" value="tuple"/>
</antcall>
<antcall target="one_shipment_example">
<param name="param_name" value="sentity"/>
</antcall>
<antcall target="one_shipment_example">
<param name="param_name" value="marshal"/>
</antcall>
<antcall target="one_shipment_example">
<param name="param_name" value="factory"/>
</antcall>
<antcall target="one_persist_example">
<param name="param_name" value="CustomKeyOrderExample"/>
</antcall>
<antcall target="one_persist_example">
<param name="param_name" value="EventExample"/>
</antcall>
<antcall target="one_persist_example">
<param name="param_name" value="EventExampleDPL"/>
</antcall>
<antcall target="one_persist_example">
<param name="param_name" value="PersonExample"/>
</antcall>
<antcall target="DplDump">
<param name="home" value="tmp"/>
<param name="store" value="PersonStore"/>
</antcall>
</target>
<target name="one_shipment_example">
<echo message="=== ${param_name} ==="/>
<delete dir="tmp"/>
<mkdir dir="tmp"/>
<java dir="." fork="yes" classpathref="classpath"
classname="collections.ship.${param_name}.Sample"/>
</target>
<target name="one_persist_example">
<echo message="=== ${param_name} ==="/>
<delete dir="tmp"/>
<mkdir dir="tmp"/>
<java fork="yes" dir="." classname="persist.${param_name}">
<jvmarg value="-ea"/>
<arg line="-h tmp"/>
<classpath refid="classpath"/>
</java>
</target>
<target name="DplDump">
<echo message="=== DplDump ${home} ${store} ==="/>
<java fork="yes" dir="." classname="persist.DplDump">
<jvmarg value="-ea"/>
<arg line="-h ${home} -s ${store}"/>
<classpath refid="classpath"/>
</java>
</target>
<!-- Using fork="yes" does not work for AccessExample, apparently because
it is interactive and the input stream of the forked process isn't
functional; therefore this sample writes to the base directory.
-->
<target name="access_example" depends="build">
<echo message="=== AccessExample ==="/>
<java classpathref="classpath"
classname="collections.access.AccessExample">
</java>
</target>
<target name="report">
<java classname="com.cortexeb.tools.clover.reporters.html.HtmlReporter"
fork="true">
<arg line="--outputdir reports --showSrc --initstring ${clover.initstring} --title 'Berkeley DB Java BDB API'"/>
<classpath refid="clover.classpath"/>
</java>
</target>
</project>

View File

@@ -0,0 +1,126 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: MarshalledObject.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.bind.serial.test;
import java.io.Serializable;
import com.sleepycat.bind.tuple.MarshalledTupleKeyEntity;
import com.sleepycat.bind.tuple.TupleInput;
import com.sleepycat.bind.tuple.TupleOutput;
/**
* @author Mark Hayes
*/
public class MarshalledObject
implements Serializable, MarshalledTupleKeyEntity {
private String data;
private transient String primaryKey;
private String indexKey1;
private String indexKey2;
public MarshalledObject(String data, String primaryKey,
String indexKey1, String indexKey2) {
this.data = data;
this.primaryKey = primaryKey;
this.indexKey1 = indexKey1;
this.indexKey2 = indexKey2;
}
public boolean equals(Object o) {
try {
MarshalledObject other = (MarshalledObject) o;
return this.data.equals(other.data) &&
this.primaryKey.equals(other.primaryKey) &&
this.indexKey1.equals(other.indexKey1) &&
this.indexKey2.equals(other.indexKey2);
} catch (Exception e) {
return false;
}
}
public String getData() {
return data;
}
public String getPrimaryKey() {
return primaryKey;
}
public String getIndexKey1() {
return indexKey1;
}
public String getIndexKey2() {
return indexKey2;
}
public int expectedKeyLength() {
return primaryKey.length() + 1;
}
public void marshalPrimaryKey(TupleOutput keyOutput) {
keyOutput.writeString(primaryKey);
}
public void unmarshalPrimaryKey(TupleInput keyInput) {
primaryKey = keyInput.readString();
}
public boolean marshalSecondaryKey(String keyName, TupleOutput keyOutput) {
if ("1".equals(keyName)) {
if (indexKey1.length() > 0) {
keyOutput.writeString(indexKey1);
return true;
} else {
return false;
}
} else if ("2".equals(keyName)) {
if (indexKey2.length() > 0) {
keyOutput.writeString(indexKey2);
return true;
} else {
return false;
}
} else {
throw new IllegalArgumentException("Unknown keyName: " + keyName);
}
}
public boolean nullifyForeignKey(String keyName) {
if ("1".equals(keyName)) {
if (indexKey1.length() > 0) {
indexKey1 = "";
return true;
} else {
return false;
}
} else if ("2".equals(keyName)) {
if (indexKey2.length() > 0) {
indexKey2 = "";
return true;
} else {
return false;
}
} else {
throw new IllegalArgumentException("Unknown keyName: " + keyName);
}
}
}

View File

@@ -0,0 +1,43 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: NullClassCatalog.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.bind.serial.test;
import java.io.ObjectStreamClass;
import java.math.BigInteger;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.bind.serial.ClassCatalog;
/**
* NullCatalog is a dummy Catalog implementation that simply
* returns large (8 byte) class IDs so that ObjectOutput
* can be simulated when computing a serialized size.
*
* @author Mark Hayes
*/
class NullClassCatalog implements ClassCatalog {
private long id = Long.MAX_VALUE;
public void close()
throws DatabaseException {
}
public byte[] getClassID(ObjectStreamClass classFormat)
throws DatabaseException {
return BigInteger.valueOf(id--).toByteArray();
}
public ObjectStreamClass getClassFormat(byte[] classID)
throws DatabaseException, ClassNotFoundException {
return null; // ObjectInput not supported
}
}

View File

@@ -0,0 +1,327 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: SerialBindingTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.bind.serial.test;
import java.io.Serializable;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.bind.EntityBinding;
import com.sleepycat.bind.serial.ClassCatalog;
import com.sleepycat.bind.serial.SerialBinding;
import com.sleepycat.bind.serial.SerialSerialBinding;
import com.sleepycat.bind.serial.TupleSerialMarshalledBinding;
import com.sleepycat.db.DatabaseEntry;
import com.sleepycat.util.ExceptionUnwrapper;
import com.sleepycat.util.FastOutputStream;
import com.sleepycat.util.test.SharedTestUtils;
/**
* @author Mark Hayes
*/
public class SerialBindingTest extends TestCase {
private ClassCatalog catalog;
private DatabaseEntry buffer;
private DatabaseEntry keyBuffer;
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite(SerialBindingTest.class);
return suite;
}
public SerialBindingTest(String name) {
super(name);
}
public void setUp() {
SharedTestUtils.printTestName("SerialBindingTest." + getName());
catalog = new TestClassCatalog();
buffer = new DatabaseEntry();
keyBuffer = new DatabaseEntry();
}
public void tearDown() {
/* Ensure that GC can cleanup. */
catalog = null;
buffer = null;
keyBuffer = null;
}
public void runTest()
throws Throwable {
try {
super.runTest();
} catch (Exception e) {
throw ExceptionUnwrapper.unwrap(e);
}
}
private void primitiveBindingTest(Object val) {
Class cls = val.getClass();
SerialBinding binding = new SerialBinding(catalog, cls);
binding.objectToEntry(val, buffer);
assertTrue(buffer.getSize() > 0);
Object val2 = binding.entryToObject(buffer);
assertSame(cls, val2.getClass());
assertEquals(val, val2);
Object valWithWrongCls = (cls == String.class)
? ((Object) new Integer(0)) : ((Object) new String(""));
try {
binding.objectToEntry(valWithWrongCls, buffer);
} catch (IllegalArgumentException expected) {}
}
public void testPrimitiveBindings() {
primitiveBindingTest("abc");
primitiveBindingTest(new Character('a'));
primitiveBindingTest(new Boolean(true));
primitiveBindingTest(new Byte((byte) 123));
primitiveBindingTest(new Short((short) 123));
primitiveBindingTest(new Integer(123));
primitiveBindingTest(new Long(123));
primitiveBindingTest(new Float(123.123));
primitiveBindingTest(new Double(123.123));
}
public void testNullObjects() {
SerialBinding binding = new SerialBinding(catalog, null);
buffer.setSize(0);
binding.objectToEntry(null, buffer);
assertTrue(buffer.getSize() > 0);
assertEquals(null, binding.entryToObject(buffer));
}
public void testSerialSerialBinding() {
SerialBinding keyBinding = new SerialBinding(catalog, String.class);
SerialBinding valueBinding = new SerialBinding(catalog, String.class);
EntityBinding binding = new MySerialSerialBinding(keyBinding,
valueBinding);
String val = "key#value?indexKey";
binding.objectToData(val, buffer);
assertTrue(buffer.getSize() > 0);
binding.objectToKey(val, keyBuffer);
assertTrue(keyBuffer.getSize() > 0);
Object result = binding.entryToObject(keyBuffer, buffer);
assertEquals(val, result);
}
// also tests TupleSerialBinding since TupleSerialMarshalledBinding extends
// it
public void testTupleSerialMarshalledBinding() {
SerialBinding valueBinding = new SerialBinding(catalog,
MarshalledObject.class);
EntityBinding binding =
new TupleSerialMarshalledBinding(valueBinding);
MarshalledObject val = new MarshalledObject("abc", "primary",
"index1", "index2");
binding.objectToData(val, buffer);
assertTrue(buffer.getSize() > 0);
binding.objectToKey(val, keyBuffer);
assertEquals(val.expectedKeyLength(), keyBuffer.getSize());
Object result = binding.entryToObject(keyBuffer, buffer);
assertTrue(result instanceof MarshalledObject);
val = (MarshalledObject) result;
assertEquals("abc", val.getData());
assertEquals("primary", val.getPrimaryKey());
assertEquals("index1", val.getIndexKey1());
assertEquals("index2", val.getIndexKey2());
}
public void testBufferSize() {
CaptureSizeBinding binding =
new CaptureSizeBinding(catalog, String.class);
binding.objectToEntry("x", buffer);
assertEquals("x", binding.entryToObject(buffer));
assertEquals(FastOutputStream.DEFAULT_INIT_SIZE, binding.bufSize);
binding.setSerialBufferSize(1000);
binding.objectToEntry("x", buffer);
assertEquals("x", binding.entryToObject(buffer));
assertEquals(1000, binding.bufSize);
}
private static class CaptureSizeBinding extends SerialBinding {
int bufSize;
CaptureSizeBinding(ClassCatalog classCatalog, Class baseClass) {
super(classCatalog, baseClass);
}
public FastOutputStream getSerialOutput(Object object) {
FastOutputStream fos = super.getSerialOutput(object);
bufSize = fos.getBufferBytes().length;
return fos;
}
}
public void testBufferOverride() {
FastOutputStream out = new FastOutputStream(10);
CachedOutputBinding binding =
new CachedOutputBinding(catalog, String.class, out);
binding.used = false;
binding.objectToEntry("x", buffer);
assertEquals("x", binding.entryToObject(buffer));
assertTrue(binding.used);
binding.used = false;
binding.objectToEntry("aaaaaaaaaaaaaaaaaaaaaa", buffer);
assertEquals("aaaaaaaaaaaaaaaaaaaaaa", binding.entryToObject(buffer));
assertTrue(binding.used);
binding.used = false;
binding.objectToEntry("x", buffer);
assertEquals("x", binding.entryToObject(buffer));
assertTrue(binding.used);
}
private static class CachedOutputBinding extends SerialBinding {
FastOutputStream out;
boolean used;
CachedOutputBinding(ClassCatalog classCatalog,
Class baseClass,
FastOutputStream out) {
super(classCatalog, baseClass);
this.out = out;
}
public FastOutputStream getSerialOutput(Object object) {
out.reset();
used = true;
return out;
}
}
private static class MySerialSerialBinding extends SerialSerialBinding {
private MySerialSerialBinding(SerialBinding keyBinding,
SerialBinding valueBinding) {
super(keyBinding, valueBinding);
}
public Object entryToObject(Object keyInput, Object valueInput) {
return "" + keyInput + '#' + valueInput;
}
public Object objectToKey(Object object) {
String s = (String) object;
int i = s.indexOf('#');
if (i < 0 || i == s.length() - 1) {
throw new IllegalArgumentException(s);
} else {
return s.substring(0, i);
}
}
public Object objectToData(Object object) {
String s = (String) object;
int i = s.indexOf('#');
if (i < 0 || i == s.length() - 1) {
throw new IllegalArgumentException(s);
} else {
return s.substring(i + 1);
}
}
}
/**
* Tests that overriding SerialBinding.getClassLoader is possible. This is
* a crude test because to create a truly working class loader is a large
* undertaking.
*/
public void testClassloaderOverride()
throws Exception {
DatabaseEntry entry = new DatabaseEntry();
SerialBinding binding = new CustomLoaderBinding
(catalog, null, new FailureClassLoader());
try {
binding.objectToEntry(new MyClass(), entry);
binding.entryToObject(entry);
fail();
} catch (RuntimeException e) {
assertTrue(e.getMessage().startsWith("expect failure"));
}
}
private static class CustomLoaderBinding extends SerialBinding {
private ClassLoader loader;
CustomLoaderBinding(ClassCatalog classCatalog,
Class baseClass,
ClassLoader loader) {
super(classCatalog, baseClass);
this.loader = loader;
}
public ClassLoader getClassLoader() {
return loader;
}
}
private static class FailureClassLoader extends ClassLoader {
public Class loadClass(String name)
throws ClassNotFoundException {
throw new RuntimeException("expect failure: " + name);
}
}
private static class MyClass implements Serializable {
}
}

View File

@@ -0,0 +1,59 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TestClassCatalog.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.bind.serial.test;
import java.io.ObjectStreamClass;
import java.util.HashMap;
import com.sleepycat.bind.serial.ClassCatalog;
import com.sleepycat.db.DatabaseException;
/**
* @author Mark Hayes
*/
public class TestClassCatalog implements ClassCatalog {
private HashMap idToDescMap = new HashMap();
private HashMap nameToIdMap = new HashMap();
private int nextId = 1;
public TestClassCatalog() {
}
public void close()
throws DatabaseException {
}
public synchronized byte[] getClassID(ObjectStreamClass desc)
throws DatabaseException {
String className = desc.getName();
byte[] id = (byte[]) nameToIdMap.get(className);
if (id == null) {
String strId = String.valueOf(nextId);
id = strId.getBytes();
nextId += 1;
idToDescMap.put(strId, desc);
nameToIdMap.put(className, id);
}
return id;
}
public synchronized ObjectStreamClass getClassFormat(byte[] id)
throws DatabaseException {
String strId = new String(id);
ObjectStreamClass desc = (ObjectStreamClass) idToDescMap.get(strId);
if (desc == null) {
throw new DatabaseException("classID not found");
}
return desc;
}
}

View File

@@ -0,0 +1,491 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: BindingSpeedTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.bind.test;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.xml.parsers.SAXParserFactory;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import com.sleepycat.bind.serial.SerialInput;
import com.sleepycat.bind.serial.SerialOutput;
import com.sleepycat.bind.serial.test.TestClassCatalog;
import com.sleepycat.bind.tuple.TupleInput;
import com.sleepycat.bind.tuple.TupleOutput;
import com.sleepycat.util.FastInputStream;
import com.sleepycat.util.FastOutputStream;
import com.sleepycat.util.test.SharedTestUtils;
/**
* @author Mark Hayes
*/
public class BindingSpeedTest extends TestCase {
static final String JAVA_UNSHARED = "java-unshared".intern();
static final String JAVA_SHARED = "java-shared".intern();
static final String JAVA_EXTERNALIZABLE = "java-externalizable".intern();
static final String XML_SAX = "xml-sax".intern();
static final String TUPLE = "tuple".intern();
static final String REFLECT_METHOD = "reflectMethod".intern();
static final String REFLECT_FIELD = "reflectField".intern();
static final int RUN_COUNT = 1000;
static final boolean VERBOSE = false;
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite() {
TestSuite suite = new TestSuite();
suite.addTest(new BindingSpeedTest(JAVA_UNSHARED));
suite.addTest(new BindingSpeedTest(JAVA_SHARED));
suite.addTest(new BindingSpeedTest(JAVA_EXTERNALIZABLE));
suite.addTest(new BindingSpeedTest(XML_SAX));
suite.addTest(new BindingSpeedTest(TUPLE));
suite.addTest(new BindingSpeedTest(REFLECT_METHOD));
suite.addTest(new BindingSpeedTest(REFLECT_FIELD));
return suite;
}
private String command;
private FastOutputStream fo;
private TupleOutput to;
private TestClassCatalog jtc;
private byte[] buf;
private XMLReader parser;
private Method[] getters;
private Method[] setters;
private Field[] fields;
public BindingSpeedTest(String name) {
super("BindingSpeedTest." + name);
command = name;
}
public void runTest()
throws Exception {
SharedTestUtils.printTestName(getName());
boolean isTuple = false;
boolean isReflectMethod = false;
boolean isReflectField = false;
boolean isXmlSax = false;
boolean isSerial = false;
boolean isShared = false;
boolean isExternalizable = false;
if (command == TUPLE) {
isTuple = true;
} else if (command == REFLECT_METHOD) {
isReflectMethod = true;
} else if (command == REFLECT_FIELD) {
isReflectField = true;
} else if (command == XML_SAX) {
isXmlSax = true;
} else if (command == JAVA_UNSHARED) {
isSerial = true;
} else if (command == JAVA_SHARED) {
isSerial = true;
isShared = true;
} else if (command == JAVA_EXTERNALIZABLE) {
isSerial = true;
isShared = true;
isExternalizable = true;
} else {
throw new Exception("invalid command: " + command);
}
// Do initialization
if (isTuple) {
initTuple();
} else if (isReflectMethod) {
initReflectMethod();
} else if (isReflectField) {
initReflectField();
} else if (isXmlSax) {
initXmlSax();
} else if (isSerial) {
if (isShared) {
initSerialShared();
} else {
initSerialUnshared();
}
}
// Prime the Java compiler
int size = 0;
for (int i = 0; i < RUN_COUNT; i += 1) {
if (isTuple) {
size = runTuple();
} else if (isReflectMethod) {
size = runReflectMethod();
} else if (isReflectField) {
size = runReflectField();
} else if (isXmlSax) {
size = runXmlSax();
} else if (isSerial) {
if (isShared) {
if (isExternalizable) {
size = runSerialExternalizable();
} else {
size = runSerialShared();
}
} else {
size = runSerialUnshared();
}
}
}
// Then run the timing tests
long startTime = System.currentTimeMillis();
for (int i = 0; i < RUN_COUNT; i += 1) {
if (isTuple) {
size = runTuple();
} else if (isReflectMethod) {
size = runReflectMethod();
} else if (isReflectField) {
size = runReflectField();
} else if (isXmlSax) {
size = runXmlSax();
} else if (isSerial) {
if (isShared) {
if (isExternalizable) {
size = runSerialExternalizable();
} else {
size = runSerialShared();
}
} else {
size = runSerialUnshared();
}
}
}
long stopTime = System.currentTimeMillis();
assertTrue("data size too big", size < 250);
if (VERBOSE) {
System.out.println(command);
System.out.println("data size: " + size);
System.out.println("run time: " +
((stopTime - startTime) / (double) RUN_COUNT));
}
}
public void tearDown() {
/* Ensure that GC can cleanup. */
command = null;
fo = null;
to = null;
jtc = null;
buf = null;
parser = null;
}
void initSerialUnshared()
throws Exception {
fo = new FastOutputStream();
}
int runSerialUnshared()
throws Exception {
fo.reset();
ObjectOutputStream oos = new ObjectOutputStream(fo);
oos.writeObject(new Data());
byte[] bytes = fo.toByteArray();
FastInputStream fi = new FastInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(fi);
ois.readObject();
return bytes.length;
}
void initSerialShared()
throws Exception {
jtc = new TestClassCatalog();
fo = new FastOutputStream();
}
int runSerialShared()
throws Exception {
fo.reset();
SerialOutput oos = new SerialOutput(fo, jtc);
oos.writeObject(new Data());
byte[] bytes = fo.toByteArray();
FastInputStream fi = new FastInputStream(bytes);
SerialInput ois = new SerialInput(fi, jtc);
ois.readObject();
return (bytes.length - SerialOutput.getStreamHeader().length);
}
int runSerialExternalizable()
throws Exception {
fo.reset();
SerialOutput oos = new SerialOutput(fo, jtc);
oos.writeObject(new Data2());
byte[] bytes = fo.toByteArray();
FastInputStream fi = new FastInputStream(bytes);
SerialInput ois = new SerialInput(fi, jtc);
ois.readObject();
return (bytes.length - SerialOutput.getStreamHeader().length);
}
void initTuple()
throws Exception {
buf = new byte[500];
to = new TupleOutput(buf);
}
int runTuple()
throws Exception {
to.reset();
new Data().writeTuple(to);
TupleInput ti = new TupleInput(
to.getBufferBytes(), to.getBufferOffset(),
to.getBufferLength());
new Data().readTuple(ti);
return to.getBufferLength();
}
void initReflectMethod()
throws Exception {
initTuple();
Class cls = Data.class;
getters = new Method[5];
getters[0] = cls.getMethod("getField1", new Class[0]);
getters[1] = cls.getMethod("getField2", new Class[0]);
getters[2] = cls.getMethod("getField3", new Class[0]);
getters[3] = cls.getMethod("getField4", new Class[0]);
getters[4] = cls.getMethod("getField5", new Class[0]);
setters = new Method[5];
setters[0] = cls.getMethod("setField1", new Class[] {String.class});
setters[1] = cls.getMethod("setField2", new Class[] {String.class});
setters[2] = cls.getMethod("setField3", new Class[] {Integer.TYPE});
setters[3] = cls.getMethod("setField4", new Class[] {Integer.TYPE});
setters[4] = cls.getMethod("setField5", new Class[] {String.class});
}
int runReflectMethod()
throws Exception {
to.reset();
Data data = new Data();
to.writeString((String) getters[0].invoke(data, (Object[]) null));
to.writeString((String) getters[1].invoke(data, (Object[]) null));
to.writeInt(((Integer) getters[2].invoke(data, (Object[]) null)).intValue());
to.writeInt(((Integer) getters[3].invoke(data, (Object[]) null)).intValue());
to.writeString((String) getters[4].invoke(data, (Object[]) null));
TupleInput ti = new TupleInput(
to.getBufferBytes(), to.getBufferOffset(),
to.getBufferLength());
data = new Data();
setters[0].invoke(data, new Object[] {ti.readString()});
setters[1].invoke(data, new Object[] {ti.readString()});
setters[2].invoke(data, new Object[] {new Integer(ti.readInt())});
setters[3].invoke(data, new Object[] {new Integer(ti.readInt())});
setters[4].invoke(data, new Object[] {ti.readString()});
return to.getBufferLength();
}
void initReflectField()
throws Exception {
initTuple();
Class cls = Data.class;
fields = new Field[5];
fields[0] = cls.getField("field1");
fields[1] = cls.getField("field2");
fields[2] = cls.getField("field3");
fields[3] = cls.getField("field4");
fields[4] = cls.getField("field5");
}
int runReflectField()
throws Exception {
to.reset();
Data data = new Data();
to.writeString((String) fields[0].get(data));
to.writeString((String) fields[1].get(data));
to.writeInt(((Integer) fields[2].get(data)).intValue());
to.writeInt(((Integer) fields[3].get(data)).intValue());
to.writeString((String) fields[4].get(data));
TupleInput ti = new TupleInput(
to.getBufferBytes(), to.getBufferOffset(),
to.getBufferLength());
data = new Data();
fields[0].set(data, ti.readString());
fields[1].set(data, ti.readString());
fields[2].set(data, new Integer(ti.readInt()));
fields[3].set(data, new Integer(ti.readInt()));
fields[4].set(data, ti.readString());
return to.getBufferLength();
}
void initXmlSax()
throws Exception {
buf = new byte[500];
fo = new FastOutputStream();
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
saxFactory.setNamespaceAware(true);
parser = saxFactory.newSAXParser().getXMLReader();
}
int runXmlSax()
throws Exception {
fo.reset();
OutputStreamWriter writer = new OutputStreamWriter(fo);
new Data().writeXmlText(writer);
byte[] bytes = fo.toByteArray();
FastInputStream fi = new FastInputStream(bytes);
InputSource input = new InputSource(fi);
parser.parse(input);
//InputStreamReader reader = new InputStreamReader(fi);
//new Data().readXmlText(??);
return bytes.length;
}
static class Data2 extends Data implements Externalizable {
public Data2() {}
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
field1 = in.readUTF();
field2 = in.readUTF();
field3 = in.readInt();
field4 = in.readInt();
field5 = in.readUTF();
}
public void writeExternal(ObjectOutput out)
throws IOException {
out.writeUTF(field1);
out.writeUTF(field2);
out.writeInt(field3);
out.writeInt(field4);
out.writeUTF(field5);
}
}
static class Data implements Serializable {
public String field1 = "field1";
public String field2 = "field2";
public int field3 = 333;
public int field4 = 444;
public String field5 = "field5";
public String getField1() { return field1; }
public String getField2() { return field2; }
public int getField3() { return field3; }
public int getField4() { return field4; }
public String getField5() { return field5; }
public void setField1(String v) { field1 = v; }
public void setField2(String v) { field2 = v; }
public void setField3(int v) { field3 = v; }
public void setField4(int v) { field4 = v; }
public void setField5(String v) { field5 = v; }
void readTuple(TupleInput _input) {
field1 = _input.readString();
field2 = _input.readString();
field3 = _input.readInt();
field4 = _input.readInt();
field5 = _input.readString();
}
void writeTuple(TupleOutput _output) {
_output.writeString(field1);
_output.writeString(field2);
_output.writeInt(field3);
_output.writeInt(field4);
_output.writeString(field5);
}
void writeXmlText(Writer writer) throws IOException {
writer.write("<Data><Field1>");
writer.write(field1);
writer.write("</Field1><Field2>");
writer.write(field2);
writer.write("</Field2><Field3>");
writer.write(String.valueOf(field3));
writer.write("</Field3><Field4>");
writer.write(String.valueOf(field4));
writer.write("</Field4><Field5>");
writer.write(field5);
writer.write("</Field5></Data>");
writer.flush();
}
}
}

View File

@@ -0,0 +1,137 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: MarshalledObject.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.bind.tuple.test;
import com.sleepycat.bind.tuple.MarshalledTupleEntry;
import com.sleepycat.bind.tuple.MarshalledTupleKeyEntity;
import com.sleepycat.bind.tuple.TupleInput;
import com.sleepycat.bind.tuple.TupleOutput;
/**
* @author Mark Hayes
*/
public class MarshalledObject
implements MarshalledTupleEntry, MarshalledTupleKeyEntity {
private String data;
private String primaryKey;
private String indexKey1;
private String indexKey2;
public MarshalledObject() {
}
MarshalledObject(String data, String primaryKey,
String indexKey1, String indexKey2) {
this.data = data;
this.primaryKey = primaryKey;
this.indexKey1 = indexKey1;
this.indexKey2 = indexKey2;
}
String getData() {
return data;
}
String getPrimaryKey() {
return primaryKey;
}
String getIndexKey1() {
return indexKey1;
}
String getIndexKey2() {
return indexKey2;
}
int expectedDataLength() {
return data.length() + 1 +
indexKey1.length() + 1 +
indexKey2.length() + 1;
}
int expectedKeyLength() {
return primaryKey.length() + 1;
}
public void marshalEntry(TupleOutput dataOutput) {
dataOutput.writeString(data);
dataOutput.writeString(indexKey1);
dataOutput.writeString(indexKey2);
}
public void unmarshalEntry(TupleInput dataInput) {
data = dataInput.readString();
indexKey1 = dataInput.readString();
indexKey2 = dataInput.readString();
}
public void marshalPrimaryKey(TupleOutput keyOutput) {
keyOutput.writeString(primaryKey);
}
public void unmarshalPrimaryKey(TupleInput keyInput) {
primaryKey = keyInput.readString();
}
public boolean marshalSecondaryKey(String keyName, TupleOutput keyOutput) {
if ("1".equals(keyName)) {
if (indexKey1.length() > 0) {
keyOutput.writeString(indexKey1);
return true;
} else {
return false;
}
} else if ("2".equals(keyName)) {
if (indexKey1.length() > 0) {
keyOutput.writeString(indexKey2);
return true;
} else {
return false;
}
} else {
throw new IllegalArgumentException("Unknown keyName: " + keyName);
}
}
public boolean nullifyForeignKey(String keyName) {
if ("1".equals(keyName)) {
if (indexKey1.length() > 0) {
indexKey1 = "";
return true;
} else {
return false;
}
} else if ("2".equals(keyName)) {
if (indexKey1.length() > 0) {
indexKey2 = "";
return true;
} else {
return false;
}
} else {
throw new IllegalArgumentException("Unknown keyName: " + keyName);
}
}
}

View File

@@ -0,0 +1,420 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TupleBindingTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.bind.tuple.test;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import java.math.BigInteger;
import com.sleepycat.bind.EntityBinding;
import com.sleepycat.bind.EntryBinding;
import com.sleepycat.bind.tuple.BooleanBinding;
import com.sleepycat.bind.tuple.ByteBinding;
import com.sleepycat.bind.tuple.CharacterBinding;
import com.sleepycat.bind.tuple.DoubleBinding;
import com.sleepycat.bind.tuple.FloatBinding;
import com.sleepycat.bind.tuple.IntegerBinding;
import com.sleepycat.bind.tuple.LongBinding;
import com.sleepycat.bind.tuple.ShortBinding;
import com.sleepycat.bind.tuple.BigIntegerBinding;
import com.sleepycat.bind.tuple.SortedDoubleBinding;
import com.sleepycat.bind.tuple.SortedFloatBinding;
import com.sleepycat.bind.tuple.StringBinding;
import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.bind.tuple.TupleInput;
import com.sleepycat.bind.tuple.TupleInputBinding;
import com.sleepycat.bind.tuple.TupleMarshalledBinding;
import com.sleepycat.bind.tuple.TupleOutput;
import com.sleepycat.bind.tuple.TupleTupleMarshalledBinding;
import com.sleepycat.db.DatabaseEntry;
import com.sleepycat.util.FastOutputStream;
import com.sleepycat.util.ExceptionUnwrapper;
import com.sleepycat.util.test.SharedTestUtils;
/**
* @author Mark Hayes
*/
public class TupleBindingTest extends TestCase {
private DatabaseEntry buffer;
private DatabaseEntry keyBuffer;
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite(TupleBindingTest.class);
return suite;
}
public TupleBindingTest(String name) {
super(name);
}
public void setUp() {
SharedTestUtils.printTestName("TupleBindingTest." + getName());
buffer = new DatabaseEntry();
keyBuffer = new DatabaseEntry();
}
public void tearDown() {
/* Ensure that GC can cleanup. */
buffer = null;
keyBuffer = null;
}
public void runTest()
throws Throwable {
try {
super.runTest();
} catch (Exception e) {
throw ExceptionUnwrapper.unwrap(e);
}
}
private void primitiveBindingTest(Class primitiveCls, Class compareCls,
Object val, int byteSize) {
TupleBinding binding = TupleBinding.getPrimitiveBinding(primitiveCls);
/* Test standard object binding. */
binding.objectToEntry(val, buffer);
assertEquals(byteSize, buffer.getSize());
Object val2 = binding.entryToObject(buffer);
assertSame(compareCls, val2.getClass());
assertEquals(val, val2);
Object valWithWrongCls = (primitiveCls == String.class)
? ((Object) new Integer(0)) : ((Object) new String(""));
try {
binding.objectToEntry(valWithWrongCls, buffer);
}
catch (ClassCastException expected) {}
/* Test nested tuple binding. */
forMoreCoverageTest(binding, val);
}
private void forMoreCoverageTest(TupleBinding val1,Object val2) {
TupleOutput output = new TupleOutput();
output.writeString("abc");
val1.objectToEntry(val2, output);
output.writeString("xyz");
TupleInput input = new TupleInput(output);
assertEquals("abc", input.readString());
Object val3 = val1.entryToObject(input);
assertEquals("xyz", input.readString());
assertEquals(0, input.available());
assertSame(val2.getClass(), val3.getClass());
assertEquals(val2, val3);
}
public void testPrimitiveBindings() {
primitiveBindingTest(String.class, String.class,
"abc", 4);
primitiveBindingTest(Character.class, Character.class,
new Character('a'), 2);
primitiveBindingTest(Boolean.class, Boolean.class,
new Boolean(true), 1);
primitiveBindingTest(Byte.class, Byte.class,
new Byte((byte) 123), 1);
primitiveBindingTest(Short.class, Short.class,
new Short((short) 123), 2);
primitiveBindingTest(Integer.class, Integer.class,
new Integer(123), 4);
primitiveBindingTest(Long.class, Long.class,
new Long(123), 8);
primitiveBindingTest(Float.class, Float.class,
new Float(123.123), 4);
primitiveBindingTest(Double.class, Double.class,
new Double(123.123), 8);
primitiveBindingTest(Character.TYPE, Character.class,
new Character('a'), 2);
primitiveBindingTest(Boolean.TYPE, Boolean.class,
new Boolean(true), 1);
primitiveBindingTest(Byte.TYPE, Byte.class,
new Byte((byte) 123), 1);
primitiveBindingTest(Short.TYPE, Short.class,
new Short((short) 123), 2);
primitiveBindingTest(Integer.TYPE, Integer.class,
new Integer(123), 4);
primitiveBindingTest(Long.TYPE, Long.class,
new Long(123), 8);
primitiveBindingTest(Float.TYPE, Float.class,
new Float(123.123), 4);
primitiveBindingTest(Double.TYPE, Double.class,
new Double(123.123), 8);
DatabaseEntry entry = new DatabaseEntry();
StringBinding.stringToEntry("abc", entry);
assertEquals(4, entry.getData().length);
assertEquals("abc", StringBinding.entryToString(entry));
new StringBinding().objectToEntry("abc", entry);
assertEquals(4, entry.getData().length);
StringBinding.stringToEntry(null, entry);
assertEquals(2, entry.getData().length);
assertEquals(null, StringBinding.entryToString(entry));
new StringBinding().objectToEntry(null, entry);
assertEquals(2, entry.getData().length);
CharacterBinding.charToEntry('a', entry);
assertEquals(2, entry.getData().length);
assertEquals('a', CharacterBinding.entryToChar(entry));
new CharacterBinding().objectToEntry(new Character('a'), entry);
assertEquals(2, entry.getData().length);
BooleanBinding.booleanToEntry(true, entry);
assertEquals(1, entry.getData().length);
assertEquals(true, BooleanBinding.entryToBoolean(entry));
new BooleanBinding().objectToEntry(Boolean.TRUE, entry);
assertEquals(1, entry.getData().length);
ByteBinding.byteToEntry((byte) 123, entry);
assertEquals(1, entry.getData().length);
assertEquals((byte) 123, ByteBinding.entryToByte(entry));
ShortBinding.shortToEntry((short) 123, entry);
assertEquals(2, entry.getData().length);
assertEquals((short) 123, ShortBinding.entryToShort(entry));
new ByteBinding().objectToEntry(new Byte((byte) 123), entry);
assertEquals(1, entry.getData().length);
IntegerBinding.intToEntry(123, entry);
assertEquals(4, entry.getData().length);
assertEquals(123, IntegerBinding.entryToInt(entry));
new IntegerBinding().objectToEntry(new Integer(123), entry);
assertEquals(4, entry.getData().length);
LongBinding.longToEntry(123, entry);
assertEquals(8, entry.getData().length);
assertEquals(123, LongBinding.entryToLong(entry));
new LongBinding().objectToEntry(new Long(123), entry);
assertEquals(8, entry.getData().length);
FloatBinding.floatToEntry((float) 123.123, entry);
assertEquals(4, entry.getData().length);
assertTrue(((float) 123.123) == FloatBinding.entryToFloat(entry));
new FloatBinding().objectToEntry(new Float((float) 123.123), entry);
assertEquals(4, entry.getData().length);
DoubleBinding.doubleToEntry(123.123, entry);
assertEquals(8, entry.getData().length);
assertTrue(123.123 == DoubleBinding.entryToDouble(entry));
new DoubleBinding().objectToEntry(new Double(123.123), entry);
assertEquals(8, entry.getData().length);
BigIntegerBinding.bigIntegerToEntry
(new BigInteger("1234567890123456"), entry);
assertEquals(9, entry.getData().length);
assertTrue((new BigInteger("1234567890123456")).equals
(BigIntegerBinding.entryToBigInteger(entry)));
new BigIntegerBinding().objectToEntry
(new BigInteger("1234567890123456"), entry);
assertEquals(9, entry.getData().length);
forMoreCoverageTest(new BigIntegerBinding(),
new BigInteger("1234567890123456"));
SortedFloatBinding.floatToEntry((float) 123.123, entry);
assertEquals(4, entry.getData().length);
assertTrue(((float) 123.123) ==
SortedFloatBinding.entryToFloat(entry));
new SortedFloatBinding().objectToEntry
(new Float((float) 123.123), entry);
assertEquals(4, entry.getData().length);
forMoreCoverageTest(new SortedFloatBinding(),
new Float((float) 123.123));
SortedDoubleBinding.doubleToEntry(123.123, entry);
assertEquals(8, entry.getData().length);
assertTrue(123.123 == SortedDoubleBinding.entryToDouble(entry));
new SortedDoubleBinding().objectToEntry(new Double(123.123), entry);
assertEquals(8, entry.getData().length);
forMoreCoverageTest(new SortedDoubleBinding(),
new Double(123.123));
}
public void testTupleInputBinding() {
EntryBinding binding = new TupleInputBinding();
TupleOutput out = new TupleOutput();
out.writeString("abc");
binding.objectToEntry(new TupleInput(out), buffer);
assertEquals(4, buffer.getSize());
Object result = binding.entryToObject(buffer);
assertTrue(result instanceof TupleInput);
TupleInput in = (TupleInput) result;
assertEquals("abc", in.readString());
assertEquals(0, in.available());
}
// also tests TupleBinding since TupleMarshalledBinding extends it
public void testTupleMarshalledBinding() {
EntryBinding binding =
new TupleMarshalledBinding(MarshalledObject.class);
MarshalledObject val = new MarshalledObject("abc", "", "", "");
binding.objectToEntry(val, buffer);
assertEquals(val.expectedDataLength(), buffer.getSize());
Object result = binding.entryToObject(buffer);
assertTrue(result instanceof MarshalledObject);
val = (MarshalledObject) result;
assertEquals("abc", val.getData());
}
// also tests TupleTupleBinding since TupleTupleMarshalledBinding extends
// it
public void testTupleTupleMarshalledBinding() {
EntityBinding binding =
new TupleTupleMarshalledBinding(MarshalledObject.class);
MarshalledObject val = new MarshalledObject("abc", "primary",
"index1", "index2");
binding.objectToData(val, buffer);
assertEquals(val.expectedDataLength(), buffer.getSize());
binding.objectToKey(val, keyBuffer);
assertEquals(val.expectedKeyLength(), keyBuffer.getSize());
Object result = binding.entryToObject(keyBuffer, buffer);
assertTrue(result instanceof MarshalledObject);
val = (MarshalledObject) result;
assertEquals("abc", val.getData());
assertEquals("primary", val.getPrimaryKey());
assertEquals("index1", val.getIndexKey1());
assertEquals("index2", val.getIndexKey2());
}
public void testBufferSize() {
CaptureSizeBinding binding = new CaptureSizeBinding();
binding.objectToEntry("x", buffer);
assertEquals("x", binding.entryToObject(buffer));
assertEquals(FastOutputStream.DEFAULT_INIT_SIZE, binding.bufSize);
binding.setTupleBufferSize(1000);
binding.objectToEntry("x", buffer);
assertEquals("x", binding.entryToObject(buffer));
assertEquals(1000, binding.bufSize);
}
private class CaptureSizeBinding extends TupleBinding {
int bufSize;
CaptureSizeBinding() {
super();
}
public TupleOutput getTupleOutput(Object object) {
TupleOutput out = super.getTupleOutput(object);
bufSize = out.getBufferBytes().length;
return out;
}
public Object entryToObject(TupleInput input) {
return input.readString();
}
public void objectToEntry(Object object, TupleOutput output) {
assertEquals(bufSize, output.getBufferBytes().length);
output.writeString((String) object);
}
}
public void testBufferOverride() {
TupleOutput out = new TupleOutput(new byte[10]);
CachedOutputBinding binding = new CachedOutputBinding(out);
binding.used = false;
binding.objectToEntry("x", buffer);
assertEquals("x", binding.entryToObject(buffer));
assertTrue(binding.used);
binding.used = false;
binding.objectToEntry("aaaaaaaaaaaaaaaaaaaaaa", buffer);
assertEquals("aaaaaaaaaaaaaaaaaaaaaa", binding.entryToObject(buffer));
assertTrue(binding.used);
binding.used = false;
binding.objectToEntry("x", buffer);
assertEquals("x", binding.entryToObject(buffer));
assertTrue(binding.used);
}
private class CachedOutputBinding extends TupleBinding {
TupleOutput out;
boolean used;
CachedOutputBinding(TupleOutput out) {
super();
this.out = out;
}
public TupleOutput getTupleOutput(Object object) {
out.reset();
used = true;
return out;
}
public Object entryToObject(TupleInput input) {
return input.readString();
}
public void objectToEntry(Object object, TupleOutput output) {
assertSame(out, output);
output.writeString((String) object);
}
}
}

View File

@@ -0,0 +1,929 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TupleFormatTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.bind.tuple.test;
import java.util.Arrays;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.bind.tuple.TupleBinding;
import com.sleepycat.bind.tuple.TupleInput;
import com.sleepycat.bind.tuple.TupleOutput;
import com.sleepycat.db.DatabaseEntry;
import com.sleepycat.util.test.SharedTestUtils;
/**
* @author Mark Hayes
*/
public class TupleFormatTest extends TestCase {
private TupleInput in;
private TupleOutput out;
private DatabaseEntry buffer;
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite(TupleFormatTest.class);
return suite;
}
public TupleFormatTest(String name) {
super(name);
}
public void setUp() {
SharedTestUtils.printTestName("TupleFormatTest." + getName());
buffer = new DatabaseEntry();
out = new TupleOutput();
}
public void tearDown() {
/* Ensure that GC can cleanup. */
in = null;
out = null;
buffer = null;
}
private void copyOutputToInput() {
TupleBinding.outputToEntry(out, buffer);
assertEquals(out.size(), buffer.getSize());
in = TupleBinding.entryToInput(buffer);
assertEquals(in.available(), buffer.getSize());
assertEquals(in.getBufferLength(), buffer.getSize());
}
private void stringTest(String val) {
out.reset();
out.writeString(val);
assertEquals(val.length() + 1, out.size()); // assume 1-byte chars
copyOutputToInput();
assertEquals(val, in.readString());
assertEquals(0, in.available());
}
public void testString() {
stringTest("");
stringTest("a");
stringTest("abc");
out.reset();
out.writeString("abc");
out.writeString("defg");
assertEquals(9, out.size());
copyOutputToInput();
assertEquals("abc", in.readString());
assertEquals("defg", in.readString());
assertEquals(0, in.available());
out.reset();
out.writeString("abc");
out.writeString("defg");
out.writeString("hijkl");
assertEquals(15, out.size());
copyOutputToInput();
assertEquals("abc", in.readString());
assertEquals("defg", in.readString());
assertEquals("hijkl", in.readString());
assertEquals(0, in.available());
}
private void fixedStringTest(char[] val) {
out.reset();
out.writeString(val);
assertEquals(val.length, out.size()); // assume 1 byte chars
copyOutputToInput();
char[] val2 = new char[val.length];
in.readString(val2);
assertTrue(Arrays.equals(val, val2));
assertEquals(0, in.available());
in.reset();
String val3 = in.readString(val.length);
assertTrue(Arrays.equals(val, val3.toCharArray()));
assertEquals(0, in.available());
}
public void testFixedString() {
fixedStringTest(new char[0]);
fixedStringTest(new char[] {'a'});
fixedStringTest(new char[] {'a', 'b', 'c'});
out.reset();
out.writeString(new char[] {'a', 'b', 'c'});
out.writeString(new char[] {'d', 'e', 'f', 'g'});
assertEquals(7, out.size());
copyOutputToInput();
assertEquals("abc", in.readString(3));
assertEquals("defg", in.readString(4));
assertEquals(0, in.available());
out.reset();
out.writeString(new char[] {'a', 'b', 'c'});
out.writeString(new char[] {'d', 'e', 'f', 'g'});
out.writeString(new char[] {'h', 'i', 'j', 'k', 'l'});
assertEquals(12, out.size());
copyOutputToInput();
assertEquals("abc", in.readString(3));
assertEquals("defg", in.readString(4));
assertEquals("hijkl", in.readString(5));
assertEquals(0, in.available());
}
public void testNullString() {
out.reset();
out.writeString((String) null);
assertEquals(2, out.size());
copyOutputToInput();
assertEquals(null, in.readString());
assertEquals(0, in.available());
out.reset();
out.writeString((String) null);
out.writeString("x");
assertEquals(4, out.size());
copyOutputToInput();
assertEquals(null, in.readString());
assertEquals(2, in.available());
assertEquals("x", in.readString());
assertEquals(0, in.available());
out.reset();
out.writeString("x");
out.writeString((String) null);
assertEquals(4, out.size());
copyOutputToInput();
assertEquals("x", in.readString());
assertEquals(2, in.available());
assertEquals(null, in.readString());
assertEquals(0, in.available());
out.reset();
out.writeString((String) null);
out.writeInt(123);
assertEquals(6, out.size());
copyOutputToInput();
assertEquals(null, in.readString());
assertEquals(4, in.available());
assertEquals(123, in.readInt());
assertEquals(0, in.available());
out.reset();
out.writeInt(123);
out.writeString((String) null);
assertEquals(6, out.size());
copyOutputToInput();
assertEquals(123, in.readInt());
assertEquals(2, in.available());
assertEquals(null, in.readString());
assertEquals(0, in.available());
}
private void charsTest(char[] val) {
for (int mode = 0; mode < 2; mode += 1) {
out.reset();
switch (mode) {
case 0: out.writeChars(val); break;
case 1: out.writeChars(new String(val)); break;
default: throw new IllegalStateException();
}
assertEquals(val.length * 2, out.size());
copyOutputToInput();
char[] val2 = new char[val.length];
in.readChars(val2);
assertTrue(Arrays.equals(val, val2));
assertEquals(0, in.available());
in.reset();
String val3 = in.readChars(val.length);
assertTrue(Arrays.equals(val, val3.toCharArray()));
assertEquals(0, in.available());
}
}
public void testChars() {
charsTest(new char[0]);
charsTest(new char[] {'a'});
charsTest(new char[] {'a', 'b', 'c'});
out.reset();
out.writeChars("abc");
out.writeChars("defg");
assertEquals(7 * 2, out.size());
copyOutputToInput();
assertEquals("abc", in.readChars(3));
assertEquals("defg", in.readChars(4));
assertEquals(0, in.available());
out.reset();
out.writeChars("abc");
out.writeChars("defg");
out.writeChars("hijkl");
assertEquals(12 * 2, out.size());
copyOutputToInput();
assertEquals("abc", in.readChars(3));
assertEquals("defg", in.readChars(4));
assertEquals("hijkl", in.readChars(5));
assertEquals(0, in.available());
}
private void bytesTest(char[] val) {
char[] valBytes = new char[val.length];
for (int i = 0; i < val.length; i += 1)
valBytes[i] = (char) (val[i] & 0xFF);
for (int mode = 0; mode < 2; mode += 1) {
out.reset();
switch (mode) {
case 0: out.writeBytes(val); break;
case 1: out.writeBytes(new String(val)); break;
default: throw new IllegalStateException();
}
assertEquals(val.length, out.size());
copyOutputToInput();
char[] val2 = new char[val.length];
in.readBytes(val2);
assertTrue(Arrays.equals(valBytes, val2));
assertEquals(0, in.available());
in.reset();
String val3 = in.readBytes(val.length);
assertTrue(Arrays.equals(valBytes, val3.toCharArray()));
assertEquals(0, in.available());
}
}
public void testBytes() {
bytesTest(new char[0]);
bytesTest(new char[] {'a'});
bytesTest(new char[] {'a', 'b', 'c'});
bytesTest(new char[] {0x7F00, 0x7FFF, 0xFF00, 0xFFFF});
out.reset();
out.writeBytes("abc");
out.writeBytes("defg");
assertEquals(7, out.size());
copyOutputToInput();
assertEquals("abc", in.readBytes(3));
assertEquals("defg", in.readBytes(4));
assertEquals(0, in.available());
out.reset();
out.writeBytes("abc");
out.writeBytes("defg");
out.writeBytes("hijkl");
assertEquals(12, out.size());
copyOutputToInput();
assertEquals("abc", in.readBytes(3));
assertEquals("defg", in.readBytes(4));
assertEquals("hijkl", in.readBytes(5));
assertEquals(0, in.available());
}
private void booleanTest(boolean val) {
out.reset();
out.writeBoolean(val);
assertEquals(1, out.size());
copyOutputToInput();
assertEquals(val, in.readBoolean());
assertEquals(0, in.available());
}
public void testBoolean() {
booleanTest(true);
booleanTest(false);
out.reset();
out.writeBoolean(true);
out.writeBoolean(false);
assertEquals(2, out.size());
copyOutputToInput();
assertEquals(true, in.readBoolean());
assertEquals(false, in.readBoolean());
assertEquals(0, in.available());
out.reset();
out.writeBoolean(true);
out.writeBoolean(false);
out.writeBoolean(true);
assertEquals(3, out.size());
copyOutputToInput();
assertEquals(true, in.readBoolean());
assertEquals(false, in.readBoolean());
assertEquals(true, in.readBoolean());
assertEquals(0, in.available());
}
private void unsignedByteTest(int val) {
unsignedByteTest(val, val);
}
private void unsignedByteTest(int val, int expected) {
out.reset();
out.writeUnsignedByte(val);
assertEquals(1, out.size());
copyOutputToInput();
assertEquals(expected, in.readUnsignedByte());
}
public void testUnsignedByte() {
unsignedByteTest(0);
unsignedByteTest(1);
unsignedByteTest(254);
unsignedByteTest(255);
unsignedByteTest(256, 0);
unsignedByteTest(-1, 255);
unsignedByteTest(-2, 254);
unsignedByteTest(-255, 1);
out.reset();
out.writeUnsignedByte(0);
out.writeUnsignedByte(1);
out.writeUnsignedByte(255);
assertEquals(3, out.size());
copyOutputToInput();
assertEquals(0, in.readUnsignedByte());
assertEquals(1, in.readUnsignedByte());
assertEquals(255, in.readUnsignedByte());
assertEquals(0, in.available());
}
private void unsignedShortTest(int val) {
unsignedShortTest(val, val);
}
private void unsignedShortTest(int val, int expected) {
out.reset();
out.writeUnsignedShort(val);
assertEquals(2, out.size());
copyOutputToInput();
assertEquals(expected, in.readUnsignedShort());
}
public void testUnsignedShort() {
unsignedShortTest(0);
unsignedShortTest(1);
unsignedShortTest(255);
unsignedShortTest(256);
unsignedShortTest(257);
unsignedShortTest(Short.MAX_VALUE - 1);
unsignedShortTest(Short.MAX_VALUE);
unsignedShortTest(Short.MAX_VALUE + 1);
unsignedShortTest(0xFFFF - 1);
unsignedShortTest(0xFFFF);
unsignedShortTest(0xFFFF + 1, 0);
unsignedShortTest(0x7FFF0000, 0);
unsignedShortTest(0xFFFF0000, 0);
unsignedShortTest(-1, 0xFFFF);
unsignedShortTest(-2, 0xFFFF - 1);
unsignedShortTest(-0xFFFF, 1);
out.reset();
out.writeUnsignedShort(0);
out.writeUnsignedShort(1);
out.writeUnsignedShort(0xFFFF);
assertEquals(6, out.size());
copyOutputToInput();
assertEquals(0, in.readUnsignedShort());
assertEquals(1, in.readUnsignedShort());
assertEquals(0xFFFF, in.readUnsignedShort());
assertEquals(0, in.available());
}
private void unsignedIntTest(long val) {
unsignedIntTest(val, val);
}
private void unsignedIntTest(long val, long expected) {
out.reset();
out.writeUnsignedInt(val);
assertEquals(4, out.size());
copyOutputToInput();
assertEquals(expected, in.readUnsignedInt());
}
public void testUnsignedInt() {
unsignedIntTest(0L);
unsignedIntTest(1L);
unsignedIntTest(255L);
unsignedIntTest(256L);
unsignedIntTest(257L);
unsignedIntTest(Short.MAX_VALUE - 1L);
unsignedIntTest(Short.MAX_VALUE);
unsignedIntTest(Short.MAX_VALUE + 1L);
unsignedIntTest(Integer.MAX_VALUE - 1L);
unsignedIntTest(Integer.MAX_VALUE);
unsignedIntTest(Integer.MAX_VALUE + 1L);
unsignedIntTest(0xFFFFFFFFL - 1L);
unsignedIntTest(0xFFFFFFFFL);
unsignedIntTest(0xFFFFFFFFL + 1L, 0L);
unsignedIntTest(0x7FFFFFFF00000000L, 0L);
unsignedIntTest(0xFFFFFFFF00000000L, 0L);
unsignedIntTest(-1, 0xFFFFFFFFL);
unsignedIntTest(-2, 0xFFFFFFFFL - 1L);
unsignedIntTest(-0xFFFFFFFFL, 1L);
out.reset();
out.writeUnsignedInt(0L);
out.writeUnsignedInt(1L);
out.writeUnsignedInt(0xFFFFFFFFL);
assertEquals(12, out.size());
copyOutputToInput();
assertEquals(0L, in.readUnsignedInt());
assertEquals(1L, in.readUnsignedInt());
assertEquals(0xFFFFFFFFL, in.readUnsignedInt());
assertEquals(0L, in.available());
}
private void byteTest(int val) {
out.reset();
out.writeByte(val);
assertEquals(1, out.size());
copyOutputToInput();
assertEquals((byte) val, in.readByte());
}
public void testByte() {
byteTest(0);
byteTest(1);
byteTest(-1);
byteTest(Byte.MAX_VALUE - 1);
byteTest(Byte.MAX_VALUE);
byteTest(Byte.MAX_VALUE + 1);
byteTest(Byte.MIN_VALUE + 1);
byteTest(Byte.MIN_VALUE);
byteTest(Byte.MIN_VALUE - 1);
byteTest(0x7F);
byteTest(0xFF);
byteTest(0x7FFF);
byteTest(0xFFFF);
byteTest(0x7FFFFFFF);
byteTest(0xFFFFFFFF);
out.reset();
out.writeByte(0);
out.writeByte(1);
out.writeByte(-1);
assertEquals(3, out.size());
copyOutputToInput();
assertEquals(0, in.readByte());
assertEquals(1, in.readByte());
assertEquals(-1, in.readByte());
assertEquals(0, in.available());
}
private void shortTest(int val) {
out.reset();
out.writeShort(val);
assertEquals(2, out.size());
copyOutputToInput();
assertEquals((short) val, in.readShort());
}
public void testShort() {
shortTest(0);
shortTest(1);
shortTest(-1);
shortTest(Short.MAX_VALUE - 1);
shortTest(Short.MAX_VALUE);
shortTest(Short.MAX_VALUE + 1);
shortTest(Short.MIN_VALUE + 1);
shortTest(Short.MIN_VALUE);
shortTest(Short.MIN_VALUE - 1);
shortTest(0x7F);
shortTest(0xFF);
shortTest(0x7FFF);
shortTest(0xFFFF);
shortTest(0x7FFFFFFF);
shortTest(0xFFFFFFFF);
out.reset();
out.writeShort(0);
out.writeShort(1);
out.writeShort(-1);
assertEquals(3 * 2, out.size());
copyOutputToInput();
assertEquals(0, in.readShort());
assertEquals(1, in.readShort());
assertEquals(-1, in.readShort());
assertEquals(0, in.available());
}
private void intTest(int val) {
out.reset();
out.writeInt(val);
assertEquals(4, out.size());
copyOutputToInput();
assertEquals((int) val, in.readInt());
}
public void testInt() {
intTest(0);
intTest(1);
intTest(-1);
intTest(Integer.MAX_VALUE - 1);
intTest(Integer.MAX_VALUE);
intTest(Integer.MAX_VALUE + 1);
intTest(Integer.MIN_VALUE + 1);
intTest(Integer.MIN_VALUE);
intTest(Integer.MIN_VALUE - 1);
intTest(0x7F);
intTest(0xFF);
intTest(0x7FFF);
intTest(0xFFFF);
intTest(0x7FFFFFFF);
intTest(0xFFFFFFFF);
out.reset();
out.writeInt(0);
out.writeInt(1);
out.writeInt(-1);
assertEquals(3 * 4, out.size());
copyOutputToInput();
assertEquals(0, in.readInt());
assertEquals(1, in.readInt());
assertEquals(-1, in.readInt());
assertEquals(0, in.available());
}
private void longTest(long val) {
out.reset();
out.writeLong(val);
assertEquals(8, out.size());
copyOutputToInput();
assertEquals((long) val, in.readLong());
}
public void testLong() {
longTest(0);
longTest(1);
longTest(-1);
longTest(Long.MAX_VALUE - 1);
longTest(Long.MAX_VALUE);
longTest(Long.MAX_VALUE + 1);
longTest(Long.MIN_VALUE + 1);
longTest(Long.MIN_VALUE);
longTest(Long.MIN_VALUE - 1);
longTest(0x7F);
longTest(0xFF);
longTest(0x7FFF);
longTest(0xFFFF);
longTest(0x7FFFFFFF);
longTest(0xFFFFFFFF);
longTest(0x7FFFFFFFFFFFFFFFL);
longTest(0xFFFFFFFFFFFFFFFFL);
out.reset();
out.writeLong(0);
out.writeLong(1);
out.writeLong(-1);
assertEquals(3 * 8, out.size());
copyOutputToInput();
assertEquals(0, in.readLong());
assertEquals(1, in.readLong());
assertEquals(-1, in.readLong());
assertEquals(0, in.available());
}
private void floatTest(double val) {
out.reset();
out.writeFloat((float) val);
assertEquals(4, out.size());
copyOutputToInput();
if (Double.isNaN(val)) {
assertTrue(Float.isNaN(in.readFloat()));
} else {
assertEquals((float) val, in.readFloat(), 0);
}
}
public void testFloat() {
floatTest(0);
floatTest(1);
floatTest(-1);
floatTest(1.0);
floatTest(0.1);
floatTest(-1.0);
floatTest(-0.1);
floatTest(Float.NaN);
floatTest(Float.NEGATIVE_INFINITY);
floatTest(Float.POSITIVE_INFINITY);
floatTest(Short.MAX_VALUE);
floatTest(Short.MIN_VALUE);
floatTest(Integer.MAX_VALUE);
floatTest(Integer.MIN_VALUE);
floatTest(Long.MAX_VALUE);
floatTest(Long.MIN_VALUE);
floatTest(Float.MAX_VALUE);
floatTest(Float.MAX_VALUE + 1);
floatTest(Float.MIN_VALUE + 1);
floatTest(Float.MIN_VALUE);
floatTest(Float.MIN_VALUE - 1);
floatTest(0x7F);
floatTest(0xFF);
floatTest(0x7FFF);
floatTest(0xFFFF);
floatTest(0x7FFFFFFF);
floatTest(0xFFFFFFFF);
floatTest(0x7FFFFFFFFFFFFFFFL);
floatTest(0xFFFFFFFFFFFFFFFFL);
out.reset();
out.writeFloat(0);
out.writeFloat(1);
out.writeFloat(-1);
assertEquals(3 * 4, out.size());
copyOutputToInput();
assertEquals(0, in.readFloat(), 0);
assertEquals(1, in.readFloat(), 0);
assertEquals(-1, in.readFloat(), 0);
assertEquals(0, in.available(), 0);
}
private void doubleTest(double val) {
out.reset();
out.writeDouble((double) val);
assertEquals(8, out.size());
copyOutputToInput();
if (Double.isNaN(val)) {
assertTrue(Double.isNaN(in.readDouble()));
} else {
assertEquals((double) val, in.readDouble(), 0);
}
}
public void testDouble() {
doubleTest(0);
doubleTest(1);
doubleTest(-1);
doubleTest(1.0);
doubleTest(0.1);
doubleTest(-1.0);
doubleTest(-0.1);
doubleTest(Double.NaN);
doubleTest(Double.NEGATIVE_INFINITY);
doubleTest(Double.POSITIVE_INFINITY);
doubleTest(Short.MAX_VALUE);
doubleTest(Short.MIN_VALUE);
doubleTest(Integer.MAX_VALUE);
doubleTest(Integer.MIN_VALUE);
doubleTest(Long.MAX_VALUE);
doubleTest(Long.MIN_VALUE);
doubleTest(Float.MAX_VALUE);
doubleTest(Float.MIN_VALUE);
doubleTest(Double.MAX_VALUE - 1);
doubleTest(Double.MAX_VALUE);
doubleTest(Double.MAX_VALUE + 1);
doubleTest(Double.MIN_VALUE + 1);
doubleTest(Double.MIN_VALUE);
doubleTest(Double.MIN_VALUE - 1);
doubleTest(0x7F);
doubleTest(0xFF);
doubleTest(0x7FFF);
doubleTest(0xFFFF);
doubleTest(0x7FFFFFFF);
doubleTest(0xFFFFFFFF);
doubleTest(0x7FFFFFFFFFFFFFFFL);
doubleTest(0xFFFFFFFFFFFFFFFFL);
out.reset();
out.writeDouble(0);
out.writeDouble(1);
out.writeDouble(-1);
assertEquals(3 * 8, out.size());
copyOutputToInput();
assertEquals(0, in.readDouble(), 0);
assertEquals(1, in.readDouble(), 0);
assertEquals(-1, in.readDouble(), 0);
assertEquals(0, in.available(), 0);
}
private void sortedFloatTest(double val) {
out.reset();
out.writeSortedFloat((float) val);
assertEquals(4, out.size());
copyOutputToInput();
if (Double.isNaN(val)) {
assertTrue(Float.isNaN(in.readSortedFloat()));
} else {
assertEquals((float) val, in.readSortedFloat(), 0);
}
}
public void testSortedFloat() {
sortedFloatTest(0);
sortedFloatTest(1);
sortedFloatTest(-1);
sortedFloatTest(1.0);
sortedFloatTest(0.1);
sortedFloatTest(-1.0);
sortedFloatTest(-0.1);
sortedFloatTest(Float.NaN);
sortedFloatTest(Float.NEGATIVE_INFINITY);
sortedFloatTest(Float.POSITIVE_INFINITY);
sortedFloatTest(Short.MAX_VALUE);
sortedFloatTest(Short.MIN_VALUE);
sortedFloatTest(Integer.MAX_VALUE);
sortedFloatTest(Integer.MIN_VALUE);
sortedFloatTest(Long.MAX_VALUE);
sortedFloatTest(Long.MIN_VALUE);
sortedFloatTest(Float.MAX_VALUE);
sortedFloatTest(Float.MAX_VALUE + 1);
sortedFloatTest(Float.MIN_VALUE + 1);
sortedFloatTest(Float.MIN_VALUE);
sortedFloatTest(Float.MIN_VALUE - 1);
sortedFloatTest(0x7F);
sortedFloatTest(0xFF);
sortedFloatTest(0x7FFF);
sortedFloatTest(0xFFFF);
sortedFloatTest(0x7FFFFFFF);
sortedFloatTest(0xFFFFFFFF);
sortedFloatTest(0x7FFFFFFFFFFFFFFFL);
sortedFloatTest(0xFFFFFFFFFFFFFFFFL);
out.reset();
out.writeSortedFloat(0);
out.writeSortedFloat(1);
out.writeSortedFloat(-1);
assertEquals(3 * 4, out.size());
copyOutputToInput();
assertEquals(0, in.readSortedFloat(), 0);
assertEquals(1, in.readSortedFloat(), 0);
assertEquals(-1, in.readSortedFloat(), 0);
assertEquals(0, in.available(), 0);
}
private void sortedDoubleTest(double val) {
out.reset();
out.writeSortedDouble((double) val);
assertEquals(8, out.size());
copyOutputToInput();
if (Double.isNaN(val)) {
assertTrue(Double.isNaN(in.readSortedDouble()));
} else {
assertEquals((double) val, in.readSortedDouble(), 0);
}
}
public void testSortedDouble() {
sortedDoubleTest(0);
sortedDoubleTest(1);
sortedDoubleTest(-1);
sortedDoubleTest(1.0);
sortedDoubleTest(0.1);
sortedDoubleTest(-1.0);
sortedDoubleTest(-0.1);
sortedDoubleTest(Double.NaN);
sortedDoubleTest(Double.NEGATIVE_INFINITY);
sortedDoubleTest(Double.POSITIVE_INFINITY);
sortedDoubleTest(Short.MAX_VALUE);
sortedDoubleTest(Short.MIN_VALUE);
sortedDoubleTest(Integer.MAX_VALUE);
sortedDoubleTest(Integer.MIN_VALUE);
sortedDoubleTest(Long.MAX_VALUE);
sortedDoubleTest(Long.MIN_VALUE);
sortedDoubleTest(Float.MAX_VALUE);
sortedDoubleTest(Float.MIN_VALUE);
sortedDoubleTest(Double.MAX_VALUE - 1);
sortedDoubleTest(Double.MAX_VALUE);
sortedDoubleTest(Double.MAX_VALUE + 1);
sortedDoubleTest(Double.MIN_VALUE + 1);
sortedDoubleTest(Double.MIN_VALUE);
sortedDoubleTest(Double.MIN_VALUE - 1);
sortedDoubleTest(0x7F);
sortedDoubleTest(0xFF);
sortedDoubleTest(0x7FFF);
sortedDoubleTest(0xFFFF);
sortedDoubleTest(0x7FFFFFFF);
sortedDoubleTest(0xFFFFFFFF);
sortedDoubleTest(0x7FFFFFFFFFFFFFFFL);
sortedDoubleTest(0xFFFFFFFFFFFFFFFFL);
out.reset();
out.writeSortedDouble(0);
out.writeSortedDouble(1);
out.writeSortedDouble(-1);
assertEquals(3 * 8, out.size());
copyOutputToInput();
assertEquals(0, in.readSortedDouble(), 0);
assertEquals(1, in.readSortedDouble(), 0);
assertEquals(-1, in.readSortedDouble(), 0);
assertEquals(0, in.available(), 0);
}
private void packedIntTest(int val, int size) {
out.reset();
out.writePackedInt(val);
assertEquals(size, out.size());
copyOutputToInput();
assertEquals(size, in.getPackedIntByteLength());
assertEquals(val, in.readPackedInt());
}
public void testPackedInt() {
/* Exhaustive value testing is in PackedIntTest. */
packedIntTest(119, 1);
packedIntTest(0xFFFF + 119, 3);
packedIntTest(Integer.MAX_VALUE, 5);
out.reset();
out.writePackedInt(119);
out.writePackedInt(0xFFFF + 119);
out.writePackedInt(Integer.MAX_VALUE);
assertEquals(1 + 3 + 5, out.size());
copyOutputToInput();
assertEquals(119, in.readPackedInt(), 0);
assertEquals(0xFFFF + 119, in.readPackedInt(), 0);
assertEquals(Integer.MAX_VALUE, in.readPackedInt(), 0);
assertEquals(0, in.available(), 0);
}
private void packedLongTest(long val, int size) {
out.reset();
out.writePackedLong(val);
assertEquals(size, out.size());
copyOutputToInput();
assertEquals(size, in.getPackedLongByteLength());
assertEquals(val, in.readPackedLong());
}
public void testPackedLong() {
/* Exhaustive value testing is in PackedIntTest. */
packedLongTest(119, 1);
packedLongTest(0xFFFFFFFFL + 119, 5);
packedLongTest(Long.MAX_VALUE, 9);
out.reset();
out.writePackedLong(119);
out.writePackedLong(0xFFFFFFFFL + 119);
out.writePackedLong(Long.MAX_VALUE);
assertEquals(1 + 5 + 9, out.size());
copyOutputToInput();
assertEquals(119, in.readPackedLong(), 0);
assertEquals(0xFFFFFFFFL + 119, in.readPackedLong(), 0);
assertEquals(Long.MAX_VALUE, in.readPackedLong(), 0);
assertEquals(0, in.available(), 0);
}
}

View File

@@ -0,0 +1,464 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TupleOrderingTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.bind.tuple.test;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.bind.tuple.TupleOutput;
import com.sleepycat.util.test.SharedTestUtils;
/**
* @author Mark Hayes
*/
public class TupleOrderingTest extends TestCase {
private TupleOutput out;
private byte[] prevBuf;
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite(TupleOrderingTest.class);
return suite;
}
public TupleOrderingTest(String name) {
super(name);
}
public void setUp() {
SharedTestUtils.printTestName("TupleOrderingTest." + getName());
out = new TupleOutput();
prevBuf = null;
}
public void tearDown() {
/* Ensure that GC can cleanup. */
out = null;
prevBuf = null;
}
/**
* Each tuple written must be strictly less than (by comparison of bytes)
* the tuple written just before it. The check() method compares bytes
* just written to those written before the previous call to check().
*/
private void check() {
check(-1);
}
private void check(int dataIndex) {
byte[] buf = new byte[out.size()];
System.arraycopy(out.getBufferBytes(), out.getBufferOffset(),
buf, 0, buf.length);
if (prevBuf != null) {
int errOffset = -1;
int len = Math.min(prevBuf.length, buf.length);
boolean areEqual = true;
for (int i = 0; i < len; i += 1) {
int val1 = prevBuf[i] & 0xFF;
int val2 = buf[i] & 0xFF;
if (val1 < val2) {
areEqual = false;
break;
} else if (val1 > val2) {
errOffset = i;
break;
}
}
if (areEqual) {
if (prevBuf.length < buf.length) {
areEqual = false;
} else if (prevBuf.length > buf.length) {
areEqual = false;
errOffset = buf.length + 1;
}
}
if (errOffset != -1 || areEqual) {
StringBuffer msg = new StringBuffer();
if (errOffset != -1) {
msg.append("Left >= right at byte offset " + errOffset);
} else if (areEqual) {
msg.append("Bytes are equal");
} else {
throw new IllegalStateException();
}
msg.append("\nLeft hex bytes: ");
for (int i = 0; i < prevBuf.length; i += 1) {
msg.append(' ');
int val = prevBuf[i] & 0xFF;
if ((val & 0xF0) == 0) {
msg.append('0');
}
msg.append(Integer.toHexString(val));
}
msg.append("\nRight hex bytes:");
for (int i = 0; i < buf.length; i += 1) {
msg.append(' ');
int val = buf[i] & 0xFF;
if ((val & 0xF0) == 0) {
msg.append('0');
}
msg.append(Integer.toHexString(val));
}
if (dataIndex >= 0) {
msg.append("\nData index: " + dataIndex);
}
fail(msg.toString());
}
}
prevBuf = buf;
out.reset();
}
private void reset() {
prevBuf = null;
out.reset();
}
public void testString() {
final String[] DATA = {
"", "a", "ab", "b", "bb", "bba",
new String(new char[] { 0x7F }),
new String(new char[] { 0x7F, 0 }),
new String(new char[] { 0xFF }),
new String(new char[] { Character.MAX_VALUE }),
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeString(DATA[i]);
check(i);
}
reset();
out.writeString("a");
check();
out.writeString("a");
out.writeString("");
check();
out.writeString("a");
out.writeString("");
out.writeString("a");
check();
out.writeString("a");
out.writeString("b");
check();
out.writeString("aa");
check();
out.writeString("b");
check();
}
public void testFixedString() {
final char[][] DATA = {
{}, {'a'}, {'a', 'b'}, {'b'}, {'b', 'b'}, {0x7F}, {0xFF},
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeString(DATA[i]);
check(i);
}
}
public void testChars() {
final char[][] DATA = {
{}, {0}, {'a'}, {'a', 0}, {'a', 'b'}, {'b'}, {'b', 'b'},
{0x7F}, {0x7F, 0}, {0xFF}, {0xFF, 0},
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeChars(DATA[i]);
check(i);
}
}
public void testBytes() {
final char[][] DATA = {
{}, {0}, {'a'}, {'a', 0}, {'a', 'b'}, {'b'}, {'b', 'b'},
{0x7F}, {0xFF},
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeBytes(DATA[i]);
check(i);
}
}
public void testBoolean() {
final boolean[] DATA = {
false, true
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeBoolean(DATA[i]);
check(i);
}
}
public void testUnsignedByte() {
final int[] DATA = {
0, 1, 0x7F, 0xFF
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeUnsignedByte(DATA[i]);
check(i);
}
}
public void testUnsignedShort() {
final int[] DATA = {
0, 1, 0xFE, 0xFF, 0x800, 0x7FFF, 0xFFFF
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeUnsignedShort(DATA[i]);
check(i);
}
}
public void testUnsignedInt() {
final long[] DATA = {
0, 1, 0xFE, 0xFF, 0x800, 0x7FFF, 0xFFFF, 0x80000,
0x7FFFFFFF, 0x80000000, 0xFFFFFFFF
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeUnsignedInt(DATA[i]);
check(i);
}
}
public void testByte() {
final byte[] DATA = {
Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
-1, 0, 1,
Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeByte(DATA[i]);
check(i);
}
}
public void testShort() {
final short[] DATA = {
Short.MIN_VALUE, Short.MIN_VALUE + 1,
Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
-1, 0, 1,
Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
Short.MAX_VALUE - 1, Short.MAX_VALUE,
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeShort(DATA[i]);
check(i);
}
}
public void testInt() {
final int[] DATA = {
Integer.MIN_VALUE, Integer.MIN_VALUE + 1,
Short.MIN_VALUE, Short.MIN_VALUE + 1,
Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
-1, 0, 1,
Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
Short.MAX_VALUE - 1, Short.MAX_VALUE,
Integer.MAX_VALUE - 1, Integer.MAX_VALUE,
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeInt(DATA[i]);
check(i);
}
}
public void testLong() {
final long[] DATA = {
Long.MIN_VALUE, Long.MIN_VALUE + 1,
Integer.MIN_VALUE, Integer.MIN_VALUE + 1,
Short.MIN_VALUE, Short.MIN_VALUE + 1,
Byte.MIN_VALUE, Byte.MIN_VALUE + 1,
-1, 0, 1,
Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
Short.MAX_VALUE - 1, Short.MAX_VALUE,
Integer.MAX_VALUE - 1, Integer.MAX_VALUE,
Long.MAX_VALUE - 1, Long.MAX_VALUE,
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeLong(DATA[i]);
check(i);
}
}
public void testFloat() {
// Only positive floats and doubles are ordered deterministically
final float[] DATA = {
0, Float.MIN_VALUE, 2 * Float.MIN_VALUE,
(float) 0.01, (float) 0.02, (float) 0.99,
1, (float) 1.01, (float) 1.02, (float) 1.99,
Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
Short.MAX_VALUE - 1, Short.MAX_VALUE,
Integer.MAX_VALUE,
Long.MAX_VALUE / 2, Long.MAX_VALUE,
Float.MAX_VALUE,
Float.POSITIVE_INFINITY,
Float.NaN,
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeFloat(DATA[i]);
check(i);
}
}
public void testDouble() {
// Only positive floats and doubles are ordered deterministically
final double[] DATA = {
0, Double.MIN_VALUE, 2 * Double.MIN_VALUE,
0.001, 0.002, 0.999,
1, 1.001, 1.002, 1.999,
Byte.MAX_VALUE - 1, Byte.MAX_VALUE,
Short.MAX_VALUE - 1, Short.MAX_VALUE,
Integer.MAX_VALUE - 1, Integer.MAX_VALUE,
Long.MAX_VALUE / 2, Long.MAX_VALUE,
Float.MAX_VALUE, Double.MAX_VALUE,
Double.POSITIVE_INFINITY,
Double.NaN,
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeDouble(DATA[i]);
check(i);
}
}
public void testSortedFloat() {
final float[] DATA = {
Float.NEGATIVE_INFINITY,
(- Float.MAX_VALUE),
Long.MIN_VALUE,
Long.MIN_VALUE / 2,
Integer.MIN_VALUE,
Short.MIN_VALUE,
Short.MIN_VALUE + 1,
Byte.MIN_VALUE,
Byte.MIN_VALUE + 1,
(float) -1.99,
(float) -1.02,
(float) -1.01,
-1,
(float) -0.99,
(float) -0.02,
(float) -0.01,
2 * (- Float.MIN_VALUE),
(- Float.MIN_VALUE),
0,
Float.MIN_VALUE,
2 * Float.MIN_VALUE,
(float) 0.01,
(float) 0.02,
(float) 0.99,
1,
(float) 1.01,
(float) 1.02,
(float) 1.99,
Byte.MAX_VALUE - 1,
Byte.MAX_VALUE,
Short.MAX_VALUE - 1,
Short.MAX_VALUE,
Integer.MAX_VALUE,
Long.MAX_VALUE / 2,
Long.MAX_VALUE,
Float.MAX_VALUE,
Float.POSITIVE_INFINITY,
Float.NaN,
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeSortedFloat(DATA[i]);
check(i);
}
}
public void testSortedDouble() {
final double[] DATA = {
Double.NEGATIVE_INFINITY,
(- Double.MAX_VALUE),
(- Float.MAX_VALUE),
Long.MIN_VALUE,
Long.MIN_VALUE / 2,
Integer.MIN_VALUE,
Short.MIN_VALUE,
Short.MIN_VALUE + 1,
Byte.MIN_VALUE,
Byte.MIN_VALUE + 1,
-1.999,
-1.002,
-1.001,
-1,
-0.999,
-0.002,
-0.001,
2 * (- Double.MIN_VALUE),
(- Double.MIN_VALUE),
0,
Double.MIN_VALUE,
2 * Double.MIN_VALUE,
0.001,
0.002,
0.999,
1,
1.001,
1.002,
1.999,
Byte.MAX_VALUE - 1,
Byte.MAX_VALUE,
Short.MAX_VALUE - 1,
Short.MAX_VALUE,
Integer.MAX_VALUE - 1,
Integer.MAX_VALUE,
Long.MAX_VALUE / 2,
Long.MAX_VALUE,
Float.MAX_VALUE,
Double.MAX_VALUE,
Double.POSITIVE_INFINITY,
Double.NaN,
};
for (int i = 0; i < DATA.length; i += 1) {
out.writeSortedDouble(DATA[i]);
check(i);
}
}
}

View File

@@ -0,0 +1,443 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: KeyRangeTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections;
import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.bind.ByteArrayBinding;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.DatabaseEntry;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
import com.sleepycat.db.OperationStatus;
import com.sleepycat.util.keyrange.KeyRange;
import com.sleepycat.util.keyrange.KeyRangeException;
import com.sleepycat.util.test.SharedTestUtils;
/**
* @author Mark Hayes
*/
public class KeyRangeTest extends TestCase {
private static boolean VERBOSE = false;
private static final byte FF = (byte) 0xFF;
private static final byte[][] KEYS = {
/* 0 */ {1},
/* 1 */ {FF},
/* 2 */ {FF, 0},
/* 3 */ {FF, 0x7F},
/* 4 */ {FF, FF},
/* 5 */ {FF, FF, 0},
/* 6 */ {FF, FF, 0x7F},
/* 7 */ {FF, FF, FF},
};
private static byte[][] EXTREME_KEY_BYTES = {
/* 0 */ {0},
/* 1 */ {FF, FF, FF, FF},
};
private Environment env;
private Database store;
private DataView view;
private DataCursor cursor;
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite() {
return new TestSuite(KeyRangeTest.class);
}
public KeyRangeTest(String name) {
super(name);
}
public void setUp()
throws Exception {
SharedTestUtils.printTestName(SharedTestUtils.qualifiedTestName(this));
}
private void openDb(Comparator comparator)
throws Exception {
File dir = SharedTestUtils.getNewDir();
ByteArrayBinding dataBinding = new ByteArrayBinding();
EnvironmentConfig envConfig = new EnvironmentConfig();
envConfig.setAllowCreate(true);
DbCompat.setInitializeCache(envConfig, true);
env = new Environment(dir, envConfig);
DatabaseConfig dbConfig = new DatabaseConfig();
DbCompat.setTypeBtree(dbConfig);
dbConfig.setAllowCreate(true);
if (comparator != null) {
DbCompat.setBtreeComparator(dbConfig, comparator);
}
store = DbCompat.testOpenDatabase
(env, null, "test.db", null, dbConfig);
view = new DataView(store, dataBinding, dataBinding, null, true, null);
}
private void closeDb()
throws Exception {
store.close();
store = null;
env.close();
env = null;
}
public void tearDown()
throws Exception {
try {
if (store != null) {
store.close();
}
} catch (Exception e) {
System.out.println("Exception ignored during close: " + e);
}
try {
if (env != null) {
env.close();
}
} catch (Exception e) {
System.out.println("Exception ignored during close: " + e);
}
/* Ensure that GC can cleanup. */
env = null;
store = null;
view = null;
cursor = null;
}
public void testScan() throws Exception {
openDb(null);
doScan(false);
closeDb();
}
public void testScanComparator() throws Exception {
openDb(new ReverseComparator());
doScan(true);
closeDb();
}
private void doScan(boolean reversed) throws Exception {
byte[][] keys = new byte[KEYS.length][];
final int end = KEYS.length - 1;
cursor = new DataCursor(view, true);
for (int i = 0; i <= end; i++) {
keys[i] = KEYS[i];
cursor.put(keys[i], KEYS[i], null, false);
}
cursor.close();
byte[][] extremeKeys = new byte[EXTREME_KEY_BYTES.length][];
for (int i = 0; i < extremeKeys.length; i++) {
extremeKeys[i] = EXTREME_KEY_BYTES[i];
}
// with empty range
cursor = new DataCursor(view, false);
expectRange(KEYS, 0, end, reversed);
cursor.close();
// begin key only, inclusive
for (int i = 0; i <= end; i++) {
cursor = newCursor(view, keys[i], true, null, false, reversed);
expectRange(KEYS, i, end, reversed);
cursor.close();
}
// begin key only, exclusive
for (int i = 0; i <= end; i++) {
cursor = newCursor(view, keys[i], false, null, false, reversed);
expectRange(KEYS, i + 1, end, reversed);
cursor.close();
}
// end key only, inclusive
for (int i = 0; i <= end; i++) {
cursor = newCursor(view, null, false, keys[i], true, reversed);
expectRange(KEYS, 0, i, reversed);
cursor.close();
}
// end key only, exclusive
for (int i = 0; i <= end; i++) {
cursor = newCursor(view, null, false, keys[i], false, reversed);
expectRange(KEYS, 0, i - 1, reversed);
cursor.close();
}
// begin and end keys, inclusive and exclusive
for (int i = 0; i <= end; i++) {
for (int j = i; j <= end; j++) {
// begin inclusive, end inclusive
cursor = newCursor(view, keys[i], true, keys[j],
true, reversed);
expectRange(KEYS, i, j, reversed);
cursor.close();
// begin inclusive, end exclusive
cursor = newCursor(view, keys[i], true, keys[j],
false, reversed);
expectRange(KEYS, i, j - 1, reversed);
cursor.close();
// begin exclusive, end inclusive
cursor = newCursor(view, keys[i], false, keys[j],
true, reversed);
expectRange(KEYS, i + 1, j, reversed);
cursor.close();
// begin exclusive, end exclusive
cursor = newCursor(view, keys[i], false, keys[j],
false, reversed);
expectRange(KEYS, i + 1, j - 1, reversed);
cursor.close();
}
}
// single key range
for (int i = 0; i <= end; i++) {
cursor = new DataCursor(view, false, keys[i]);
expectRange(KEYS, i, i, reversed);
cursor.close();
}
// start with lower extreme (before any existing key)
cursor = newCursor(view, extremeKeys[0], true, null, false, reversed);
expectRange(KEYS, 0, end, reversed);
cursor.close();
// start with higher extreme (after any existing key)
cursor = newCursor(view, null, false, extremeKeys[1], true, reversed);
expectRange(KEYS, 0, end, reversed);
cursor.close();
}
private DataCursor newCursor(DataView view,
Object beginKey, boolean beginInclusive,
Object endKey, boolean endInclusive,
boolean reversed)
throws Exception {
if (reversed) {
return new DataCursor(view, false,
endKey, endInclusive,
beginKey, beginInclusive);
} else {
return new DataCursor(view, false,
beginKey, beginInclusive,
endKey, endInclusive);
}
}
private void expectRange(byte[][] bytes, int first, int last,
boolean reversed)
throws DatabaseException {
int i;
boolean init;
for (init = true, i = first;; i++, init = false) {
if (checkRange(bytes, first, last, i <= last,
reversed, !reversed, init, i)) {
break;
}
}
for (init = true, i = last;; i--, init = false) {
if (checkRange(bytes, first, last, i >= first,
reversed, reversed, init, i)) {
break;
}
}
}
private boolean checkRange(byte[][] bytes, int first, int last,
boolean inRange, boolean reversed,
boolean forward, boolean init,
int i)
throws DatabaseException {
OperationStatus s;
if (forward) {
if (init) {
s = cursor.getFirst(false);
} else {
s = cursor.getNext(false);
}
} else {
if (init) {
s = cursor.getLast(false);
} else {
s = cursor.getPrev(false);
}
}
String msg = " " + (forward ? "next" : "prev") + " i=" + i +
" first=" + first + " last=" + last +
(reversed ? " reversed" : " not reversed");
// check that moving past ends doesn't move the cursor
if (s == OperationStatus.SUCCESS && i == first) {
OperationStatus s2 = reversed ? cursor.getNext(false)
: cursor.getPrev(false);
assertEquals(msg, OperationStatus.NOTFOUND, s2);
}
if (s == OperationStatus.SUCCESS && i == last) {
OperationStatus s2 = reversed ? cursor.getPrev(false)
: cursor.getNext(false);
assertEquals(msg, OperationStatus.NOTFOUND, s2);
}
byte[] val = (s == OperationStatus.SUCCESS)
? ((byte[]) cursor.getCurrentValue())
: null;
if (inRange) {
assertNotNull("RangeNotFound" + msg, val);
if (!Arrays.equals(val, bytes[i])){
printBytes(val);
printBytes(bytes[i]);
fail("RangeKeyNotEqual" + msg);
}
if (VERBOSE) {
System.out.println("GotRange" + msg);
}
return false;
} else {
assertEquals("RangeExceeded" + msg, OperationStatus.NOTFOUND, s);
return true;
}
}
private void printBytes(byte[] bytes) {
for (int i = 0; i < bytes.length; i += 1) {
System.out.print(Integer.toHexString(bytes[i] & 0xFF));
System.out.print(' ');
}
System.out.println();
}
public void testSubRanges() {
DatabaseEntry begin = new DatabaseEntry();
DatabaseEntry begin2 = new DatabaseEntry();
DatabaseEntry end = new DatabaseEntry();
DatabaseEntry end2 = new DatabaseEntry();
KeyRange range = new KeyRange(null);
KeyRange range2;
/* Base range [1, 2] */
begin.setData(new byte[] { 1 });
end.setData(new byte[] { 2 });
range = range.subRange(begin, true, end, true);
/* Subrange (0, 1] is invalid **. */
begin2.setData(new byte[] { 0 });
end2.setData(new byte[] { 1 });
try {
range2 = range.subRange(begin2, false, end2, true);
fail();
} catch (KeyRangeException expected) {}
/* Subrange [1, 3) is invalid. */
begin2.setData(new byte[] { 1 });
end2.setData(new byte[] { 3 });
try {
range2 = range.subRange(begin2, true, end2, false);
fail();
} catch (KeyRangeException expected) {}
/* Subrange [2, 2] is valid. */
begin2.setData(new byte[] { 2 });
end2.setData(new byte[] { 2 });
range2 = range.subRange(begin2, true, end2, true);
/* Subrange [0, 1] is invalid. */
begin2.setData(new byte[] { 0 });
end2.setData(new byte[] { 1 });
try {
range2 = range.subRange(begin2, true, end2, true);
fail();
} catch (KeyRangeException expected) {}
/* Subrange (0, 3] is invalid. */
begin2.setData(new byte[] { 0 });
end2.setData(new byte[] { 3 });
try {
range2 = range.subRange(begin2, false, end2, true);
fail();
} catch (KeyRangeException expected) {}
/* Subrange [3, 3) is invalid. */
begin2.setData(new byte[] { 3 });
end2.setData(new byte[] { 3 });
try {
range2 = range.subRange(begin2, true, end2, false);
fail();
} catch (KeyRangeException expected) {}
}
public static class ReverseComparator implements Comparator {
public int compare(Object o1, Object o2) {
byte[] d1 = (byte[]) o1;
byte[] d2 = (byte[]) o2;
int cmp = KeyRange.compareBytes(d1, 0, d1.length,
d2, 0, d2.length);
if (cmp < 0) {
return 1;
} else if (cmp > 0) {
return -1;
} else {
return 0;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,129 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: DbTestUtil.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import junit.framework.TestCase;
import com.sleepycat.db.DatabaseConfig;
/**
* @author Mark Hayes
*/
public class DbTestUtil {
public static final DatabaseConfig DBCONFIG_CREATE = new DatabaseConfig();
static {
DBCONFIG_CREATE.setAllowCreate(true);
}
private static final File TEST_DIR;
static {
String dir = System.getProperty("testdestdir");
if (dir == null || dir.length() == 0) {
dir = ".";
}
TEST_DIR = new File(dir, "tmp");
}
public static void printTestName(String name) {
// don't want verbose printing for now
// System.out.println(name);
}
public static File getExistingDir(String name)
throws IOException {
File dir = new File(TEST_DIR, name);
if (!dir.exists() || !dir.isDirectory()) {
throw new IllegalStateException(
"Not an existing directory: " + dir);
}
return dir;
}
public static File getNewDir()
throws IOException {
return getNewDir("test-dir");
}
public static File getNewDir(String name)
throws IOException {
File dir = new File(TEST_DIR, name);
if (dir.isDirectory()) {
String[] files = dir.list();
if (files != null) {
for (int i = 0; i < files.length; i += 1) {
new File(dir, files[i]).delete();
}
}
} else {
dir.delete();
dir.mkdirs();
}
return dir;
}
public static File getNewFile()
throws IOException {
return getNewFile("test-file");
}
public static File getNewFile(String name)
throws IOException {
return getNewFile(TEST_DIR, name);
}
public static File getNewFile(File dir, String name)
throws IOException {
File file = new File(dir, name);
file.delete();
return file;
}
public static boolean copyResource(Class cls, String fileName, File toDir)
throws IOException {
InputStream in = cls.getResourceAsStream("testdata/" + fileName);
if (in == null) {
return false;
}
in = new BufferedInputStream(in);
File file = new File(toDir, fileName);
OutputStream out = new FileOutputStream(file);
out = new BufferedOutputStream(out);
int c;
while ((c = in.read()) >= 0) out.write(c);
in.close();
out.close();
return true;
}
public static String qualifiedTestName(TestCase test) {
String s = test.getClass().getName();
int i = s.lastIndexOf('.');
if (i >= 0) {
s = s.substring(i + 1);
}
return s + '.' + test.getName();
}
}

View File

@@ -0,0 +1,343 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: ForeignKeyTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import java.util.Map;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.bind.serial.StoredClassCatalog;
import com.sleepycat.bind.serial.TupleSerialMarshalledKeyCreator;
import com.sleepycat.bind.serial.test.MarshalledObject;
import com.sleepycat.collections.CurrentTransaction;
import com.sleepycat.collections.TupleSerialFactory;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.ForeignKeyDeleteAction;
import com.sleepycat.db.SecondaryConfig;
import com.sleepycat.db.SecondaryDatabase;
import com.sleepycat.util.ExceptionUnwrapper;
import com.sleepycat.util.RuntimeExceptionWrapper;
import com.sleepycat.util.test.SharedTestUtils;
import com.sleepycat.util.test.TestEnv;
/**
* @author Mark Hayes
*/
public class ForeignKeyTest extends TestCase {
private static final ForeignKeyDeleteAction[] ACTIONS = {
ForeignKeyDeleteAction.ABORT,
ForeignKeyDeleteAction.NULLIFY,
ForeignKeyDeleteAction.CASCADE,
};
private static final String[] ACTION_LABELS = {
"ABORT",
"NULLIFY",
"CASCADE",
};
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite();
for (int i = 0; i < TestEnv.ALL.length; i += 1) {
for (int j = 0; j < ACTIONS.length; j += 1) {
suite.addTest(new ForeignKeyTest(TestEnv.ALL[i],
ACTIONS[j],
ACTION_LABELS[j]));
}
}
return suite;
}
private TestEnv testEnv;
private Environment env;
private StoredClassCatalog catalog;
private TupleSerialFactory factory;
private Database store1;
private Database store2;
private SecondaryDatabase index1;
private SecondaryDatabase index2;
private Map storeMap1;
private Map storeMap2;
private Map indexMap1;
private Map indexMap2;
private ForeignKeyDeleteAction onDelete;
public ForeignKeyTest(TestEnv testEnv, ForeignKeyDeleteAction onDelete,
String onDeleteLabel) {
super("ForeignKeyTest-" + testEnv.getName() + '-' + onDeleteLabel);
this.testEnv = testEnv;
this.onDelete = onDelete;
}
public void setUp()
throws Exception {
SharedTestUtils.printTestName(getName());
env = testEnv.open(getName());
createDatabase();
}
public void tearDown() {
try {
if (index1 != null) {
index1.close();
}
if (index2 != null) {
index2.close();
}
if (store1 != null) {
store1.close();
}
if (store2 != null) {
store2.close();
}
if (catalog != null) {
catalog.close();
}
if (env != null) {
env.close();
}
} catch (Exception e) {
System.out.println("Ignored exception during tearDown: " + e);
} finally {
/* Ensure that GC can cleanup. */
env = null;
testEnv = null;
catalog = null;
store1 = null;
store2 = null;
index1 = null;
index2 = null;
factory = null;
storeMap1 = null;
storeMap2 = null;
indexMap1 = null;
indexMap2 = null;
}
}
public void runTest()
throws Exception {
try {
createViews();
writeAndRead();
} catch (Exception e) {
throw ExceptionUnwrapper.unwrap(e);
}
}
private void createDatabase()
throws Exception {
catalog = new StoredClassCatalog(openDb("catalog.db"));
factory = new TupleSerialFactory(catalog);
assertSame(catalog, factory.getCatalog());
store1 = openDb("store1.db");
store2 = openDb("store2.db");
index1 = openSecondaryDb(factory, "1", store1, "index1.db", null);
index2 = openSecondaryDb(factory, "2", store2, "index2.db", store1);
}
private Database openDb(String file)
throws Exception {
DatabaseConfig config = new DatabaseConfig();
DbCompat.setTypeBtree(config);
config.setTransactional(testEnv.isTxnMode());
config.setAllowCreate(true);
return DbCompat.testOpenDatabase(env, null, file, null, config);
}
private SecondaryDatabase openSecondaryDb(TupleSerialFactory factory,
String keyName,
Database primary,
String file,
Database foreignStore)
throws Exception {
TupleSerialMarshalledKeyCreator keyCreator =
factory.getKeyCreator(MarshalledObject.class, keyName);
SecondaryConfig secConfig = new SecondaryConfig();
DbCompat.setTypeBtree(secConfig);
secConfig.setTransactional(testEnv.isTxnMode());
secConfig.setAllowCreate(true);
secConfig.setKeyCreator(keyCreator);
if (foreignStore != null) {
secConfig.setForeignKeyDatabase(foreignStore);
secConfig.setForeignKeyDeleteAction(onDelete);
if (onDelete == ForeignKeyDeleteAction.NULLIFY) {
secConfig.setForeignKeyNullifier(keyCreator);
}
}
return DbCompat.testOpenSecondaryDatabase
(env, null, file, null, primary, secConfig);
}
private void createViews()
throws Exception {
storeMap1 = factory.newMap(store1, String.class,
MarshalledObject.class, true);
storeMap2 = factory.newMap(store2, String.class,
MarshalledObject.class, true);
indexMap1 = factory.newMap(index1, String.class,
MarshalledObject.class, true);
indexMap2 = factory.newMap(index2, String.class,
MarshalledObject.class, true);
}
private void writeAndRead()
throws Exception {
CurrentTransaction txn = CurrentTransaction.getInstance(env);
if (txn != null) {
txn.beginTransaction(null);
}
MarshalledObject o1 = new MarshalledObject("data1", "pk1", "ik1", "");
assertNull(storeMap1.put(null, o1));
assertEquals(o1, storeMap1.get("pk1"));
assertEquals(o1, indexMap1.get("ik1"));
MarshalledObject o2 = new MarshalledObject("data2", "pk2", "", "pk1");
assertNull(storeMap2.put(null, o2));
assertEquals(o2, storeMap2.get("pk2"));
assertEquals(o2, indexMap2.get("pk1"));
if (txn != null) {
txn.commitTransaction();
txn.beginTransaction(null);
}
/*
* store1 contains o1 with primary key "pk1" and index key "ik1".
*
* store2 contains o2 with primary key "pk2" and foreign key "pk1",
* which is the primary key of store1.
*/
if (onDelete == ForeignKeyDeleteAction.ABORT) {
/* Test that we abort trying to delete a referenced key. */
try {
storeMap1.remove("pk1");
fail();
} catch (RuntimeExceptionWrapper expected) {
assertTrue(expected.getCause() instanceof DatabaseException);
if (txn != null) {
txn.abortTransaction();
txn.beginTransaction(null);
}
}
/* Test that we can put a record into store2 with a null foreign
* key value. */
o2 = new MarshalledObject("data2", "pk2", "", "");
assertNotNull(storeMap2.put(null, o2));
assertEquals(o2, storeMap2.get("pk2"));
/* The index2 record should have been deleted since the key was set
* to null above. */
assertNull(indexMap2.get("pk1"));
/* Test that now we can delete the record in store1, since it is no
* longer referenced. */
assertNotNull(storeMap1.remove("pk1"));
assertNull(storeMap1.get("pk1"));
assertNull(indexMap1.get("ik1"));
} else if (onDelete == ForeignKeyDeleteAction.NULLIFY) {
/* Delete the referenced key. */
assertNotNull(storeMap1.remove("pk1"));
assertNull(storeMap1.get("pk1"));
assertNull(indexMap1.get("ik1"));
/* The store2 record should still exist, but should have an empty
* secondary key since it was nullified. */
o2 = (MarshalledObject) storeMap2.get("pk2");
assertNotNull(o2);
assertEquals("data2", o2.getData());
assertEquals("pk2", o2.getPrimaryKey());
assertEquals("", o2.getIndexKey1());
assertEquals("", o2.getIndexKey2());
} else if (onDelete == ForeignKeyDeleteAction.CASCADE) {
/* Delete the referenced key. */
assertNotNull(storeMap1.remove("pk1"));
assertNull(storeMap1.get("pk1"));
assertNull(indexMap1.get("ik1"));
/* The store2 record should have deleted also. */
assertNull(storeMap2.get("pk2"));
assertNull(indexMap2.get("pk1"));
} else {
throw new IllegalStateException();
}
/*
* Test that a foreign key value may not be used that is not present
* in the foreign store. "pk2" is not in store1 in this case.
*/
assertNull(storeMap1.get("pk2"));
MarshalledObject o3 = new MarshalledObject("data3", "pk3", "", "pk2");
try {
storeMap2.put(null, o3);
fail();
} catch (RuntimeExceptionWrapper expected) {
assertTrue(expected.getCause() instanceof DatabaseException);
}
if (txn != null) {
txn.commitTransaction();
}
}
}

View File

@@ -0,0 +1,230 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: IterDeadlockTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import java.util.Iterator;
import java.util.ListIterator;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.DeadlockException;
import com.sleepycat.db.Environment;
import com.sleepycat.bind.ByteArrayBinding;
import com.sleepycat.collections.TransactionRunner;
import com.sleepycat.collections.TransactionWorker;
import com.sleepycat.collections.StoredIterator;
import com.sleepycat.collections.StoredSortedMap;
import com.sleepycat.util.test.TestEnv;
/**
* Tests the fix for [#10516], where the StoredIterator constructor was not
* closing the cursor when an exception occurred. For example, a deadlock
* exception might occur if the constructor was unable to move the cursor to
* the first element.
* @author Mark Hayes
*/
public class IterDeadlockTest extends TestCase {
private static final byte[] ONE = { 1 };
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite(IterDeadlockTest.class);
return suite;
}
private Environment env;
private Database store1;
private Database store2;
private StoredSortedMap map1;
private StoredSortedMap map2;
private ByteArrayBinding binding = new ByteArrayBinding();
public IterDeadlockTest(String name) {
super(name);
}
public void setUp()
throws Exception {
env = TestEnv.TXN.open("IterDeadlockTest");
store1 = openDb("store1.db");
store2 = openDb("store2.db");
map1 = new StoredSortedMap(store1, binding, binding, true);
map2 = new StoredSortedMap(store2, binding, binding, true);
}
public void tearDown() {
if (store1 != null) {
try {
store1.close();
} catch (Exception e) {
System.out.println("Ignored exception during tearDown: " + e);
}
}
if (store2 != null) {
try {
store2.close();
} catch (Exception e) {
System.out.println("Ignored exception during tearDown: " + e);
}
}
if (env != null) {
try {
env.close();
} catch (Exception e) {
System.out.println("Ignored exception during tearDown: " + e);
}
}
/* Allow GC of DB objects in the test case. */
env = null;
store1 = null;
store2 = null;
map1 = null;
map2 = null;
}
private Database openDb(String file)
throws Exception {
DatabaseConfig config = new DatabaseConfig();
DbCompat.setTypeBtree(config);
config.setTransactional(true);
config.setAllowCreate(true);
return DbCompat.testOpenDatabase(env, null, file, null, config);
}
public void testIterDeadlock()
throws Exception {
final Object parent = new Object();
final Object child1 = new Object();
final Object child2 = new Object();
final TransactionRunner runner = new TransactionRunner(env);
runner.setMaxRetries(0);
/* Write a record in each db. */
runner.run(new TransactionWorker() {
public void doWork() throws Exception {
assertNull(map1.put(ONE, ONE));
assertNull(map2.put(ONE, ONE));
}
});
/*
* A thread to open iterator 1, then wait to be notified, then open
* iterator 2.
*/
final Thread thread1 = new Thread(new Runnable() {
public void run() {
try {
runner.run(new TransactionWorker() {
public void doWork() throws Exception {
synchronized (child1) {
ListIterator i1 =
(ListIterator) map1.values().iterator();
i1.next();
i1.set(ONE); /* Write lock. */
StoredIterator.close(i1);
synchronized (parent) { parent.notify(); }
child1.wait();
Iterator i2 = map2.values().iterator();
assertTrue(i2.hasNext());
StoredIterator.close(i2);
}
}
});
} catch (DeadlockException expected) {
} catch (Exception e) {
e.printStackTrace();
fail(e.toString());
}
}
});
/*
* A thread to open iterator 2, then wait to be notified, then open
* iterator 1.
*/
final Thread thread2 = new Thread(new Runnable() {
public void run() {
try {
runner.run(new TransactionWorker() {
public void doWork() throws Exception {
synchronized (child2) {
ListIterator i2 =
(ListIterator) map2.values().iterator();
i2.next();
i2.set(ONE); /* Write lock. */
StoredIterator.close(i2);
synchronized (parent) { parent.notify(); }
child2.wait();
Iterator i1 = map1.values().iterator();
assertTrue(i1.hasNext());
StoredIterator.close(i1);
}
}
});
} catch (DeadlockException expected) {
} catch (Exception e) {
e.printStackTrace();
fail(e.toString());
}
}
});
/*
* Open iterator 1 in thread 1, then iterator 2 in thread 2, then let
* the threads run to open the other iterators and cause a deadlock.
*/
synchronized (parent) {
thread1.start();
parent.wait();
thread2.start();
parent.wait();
synchronized (child1) { child1.notify(); }
synchronized (child2) { child2.notify(); }
thread1.join();
thread2.join();
}
/*
* Before the fix for [#10516] we would get an exception indicating
* that cursors were not closed, when closing the stores below.
*/
store1.close();
store1 = null;
store2.close();
store2 = null;
env.close();
env = null;
}
}

View File

@@ -0,0 +1,233 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: JoinTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import java.util.Map;
import junit.framework.Test;
import junit.framework.TestCase;
import com.sleepycat.bind.serial.StoredClassCatalog;
import com.sleepycat.bind.serial.test.MarshalledObject;
import com.sleepycat.collections.StoredCollection;
import com.sleepycat.collections.StoredContainer;
import com.sleepycat.collections.StoredIterator;
import com.sleepycat.collections.StoredMap;
import com.sleepycat.collections.TransactionRunner;
import com.sleepycat.collections.TransactionWorker;
import com.sleepycat.collections.TupleSerialFactory;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.Environment;
import com.sleepycat.db.SecondaryConfig;
import com.sleepycat.db.SecondaryDatabase;
import com.sleepycat.util.test.SharedTestUtils;
import com.sleepycat.util.test.TestEnv;
/**
* @author Mark Hayes
*/
public class JoinTest extends TestCase
implements TransactionWorker {
private static final String MATCH_DATA = "d4"; // matches both keys = "yes"
private static final String MATCH_KEY = "k4"; // matches both keys = "yes"
private static final String[] VALUES = {"yes", "yes"};
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
return new JoinTest();
}
private Environment env;
private TransactionRunner runner;
private StoredClassCatalog catalog;
private TupleSerialFactory factory;
private Database store;
private SecondaryDatabase index1;
private SecondaryDatabase index2;
private StoredMap storeMap;
private StoredMap indexMap1;
private StoredMap indexMap2;
public JoinTest() {
super("JoinTest");
}
public void setUp()
throws Exception {
SharedTestUtils.printTestName(getName());
env = TestEnv.TXN.open(getName());
runner = new TransactionRunner(env);
createDatabase();
}
public void tearDown() {
try {
if (index1 != null) {
index1.close();
}
if (index2 != null) {
index2.close();
}
if (store != null) {
store.close();
}
if (catalog != null) {
catalog.close();
}
if (env != null) {
env.close();
}
} catch (Exception e) {
System.out.println("Ignored exception during tearDown: " + e);
} finally {
/* Ensure that GC can cleanup. */
index1 = null;
index2 = null;
store = null;
catalog = null;
env = null;
runner = null;
factory = null;
storeMap = null;
indexMap1 = null;
indexMap2 = null;
}
}
public void runTest()
throws Exception {
runner.run(this);
}
public void doWork()
throws Exception {
createViews();
writeAndRead();
}
private void createDatabase()
throws Exception {
catalog = new StoredClassCatalog(openDb("catalog.db"));
factory = new TupleSerialFactory(catalog);
assertSame(catalog, factory.getCatalog());
store = openDb("store.db");
index1 = openSecondaryDb(store, "index1.db", "1");
index2 = openSecondaryDb(store, "index2.db", "2");
}
private Database openDb(String file)
throws Exception {
DatabaseConfig config = new DatabaseConfig();
DbCompat.setTypeBtree(config);
config.setTransactional(true);
config.setAllowCreate(true);
return DbCompat.testOpenDatabase(env, null, file, null, config);
}
private SecondaryDatabase openSecondaryDb(Database primary,
String file,
String keyName)
throws Exception {
SecondaryConfig secConfig = new SecondaryConfig();
DbCompat.setTypeBtree(secConfig);
secConfig.setTransactional(true);
secConfig.setAllowCreate(true);
DbCompat.setSortedDuplicates(secConfig, true);
secConfig.setKeyCreator(factory.getKeyCreator(MarshalledObject.class,
keyName));
return DbCompat.testOpenSecondaryDatabase
(env, null, file, null, primary, secConfig);
}
private void createViews()
throws Exception {
storeMap = factory.newMap(store, String.class,
MarshalledObject.class, true);
indexMap1 = factory.newMap(index1, String.class,
MarshalledObject.class, true);
indexMap2 = factory.newMap(index2, String.class,
MarshalledObject.class, true);
}
private void writeAndRead()
throws Exception {
// write records: Data, PrimaryKey, IndexKey1, IndexKey2
assertNull(storeMap.put(null,
new MarshalledObject("d1", "k1", "no", "yes")));
assertNull(storeMap.put(null,
new MarshalledObject("d2", "k2", "no", "no")));
assertNull(storeMap.put(null,
new MarshalledObject("d3", "k3", "no", "yes")));
assertNull(storeMap.put(null,
new MarshalledObject("d4", "k4", "yes", "yes")));
assertNull(storeMap.put(null,
new MarshalledObject("d5", "k5", "yes", "no")));
Object o;
Map.Entry e;
// join values with index maps
o = doJoin((StoredCollection) storeMap.values());
assertEquals(MATCH_DATA, ((MarshalledObject) o).getData());
// join keySet with index maps
o = doJoin((StoredCollection) storeMap.keySet());
assertEquals(MATCH_KEY, o);
// join entrySet with index maps
o = doJoin((StoredCollection) storeMap.entrySet());
e = (Map.Entry) o;
assertEquals(MATCH_KEY, e.getKey());
assertEquals(MATCH_DATA, ((MarshalledObject) e.getValue()).getData());
}
private Object doJoin(StoredCollection coll) {
StoredContainer[] indices = { indexMap1, indexMap2 };
StoredIterator i = coll.join(indices, VALUES, null);
try {
assertTrue(i.hasNext());
Object result = i.next();
assertNotNull(result);
assertFalse(i.hasNext());
return result;
} finally { i.close(); }
}
}

View File

@@ -0,0 +1,32 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: NullTransactionRunner.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import com.sleepycat.collections.TransactionRunner;
import com.sleepycat.collections.TransactionWorker;
import com.sleepycat.db.Environment;
import com.sleepycat.util.ExceptionUnwrapper;
class NullTransactionRunner extends TransactionRunner {
NullTransactionRunner(Environment env) {
super(env);
}
public void run(TransactionWorker worker)
throws Exception {
try {
worker.doWork();
} catch (Exception e) {
throw ExceptionUnwrapper.unwrap(e);
}
}
}

View File

@@ -0,0 +1,208 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: SecondaryDeadlockTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.db.Database;
import com.sleepycat.db.DeadlockException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.TransactionConfig;
import com.sleepycat.collections.StoredSortedMap;
import com.sleepycat.collections.TransactionRunner;
import com.sleepycat.collections.TransactionWorker;
import com.sleepycat.util.ExceptionUnwrapper;
import com.sleepycat.util.test.TestEnv;
/**
* Tests whether secondary access can cause a self-deadlock when reading via a
* secondary because the collections API secondary implementation in DB 4.2
* opens two cursors. Part of the problem in [#10516] was because the
* secondary get() was not done in a txn. This problem should not occur in DB
* 4.3 and JE -- an ordinary deadlock occurs instead and is detected.
*
* @author Mark Hayes
*/
public class SecondaryDeadlockTest extends TestCase {
private static final Long N_ONE = new Long(1);
private static final Long N_101 = new Long(101);
private static final int N_ITERS = 20;
private static final int MAX_RETRIES = 1000;
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite(SecondaryDeadlockTest.class);
return suite;
}
private Environment env;
private Database store;
private Database index;
private StoredSortedMap storeMap;
private StoredSortedMap indexMap;
private Exception exception;
public SecondaryDeadlockTest(String name) {
super(name);
}
public void setUp()
throws Exception {
env = TestEnv.TXN.open("SecondaryDeadlockTest");
store = TestStore.BTREE_UNIQ.open(env, "store.db");
index = TestStore.BTREE_UNIQ.openIndex(store, "index.db");
storeMap = new StoredSortedMap(store,
TestStore.BTREE_UNIQ.getKeyBinding(),
TestStore.BTREE_UNIQ.getValueBinding(),
true);
indexMap = new StoredSortedMap(index,
TestStore.BTREE_UNIQ.getKeyBinding(),
TestStore.BTREE_UNIQ.getValueBinding(),
true);
}
public void tearDown() {
if (index != null) {
try {
index.close();
} catch (Exception e) {
System.out.println("Ignored exception during tearDown: " + e);
}
}
if (store != null) {
try {
store.close();
} catch (Exception e) {
System.out.println("Ignored exception during tearDown: " + e);
}
}
if (env != null) {
try {
env.close();
} catch (Exception e) {
System.out.println("Ignored exception during tearDown: " + e);
}
}
/* Allow GC of DB objects in the test case. */
env = null;
store = null;
index = null;
storeMap = null;
indexMap = null;
}
public void testSecondaryDeadlock()
throws Exception {
final TransactionRunner runner = new TransactionRunner(env);
runner.setMaxRetries(MAX_RETRIES);
/*
* This test deadlocks a lot at degree 3 serialization. In debugging
* this I discovered it was not due to phantom prevention per se but
* just to a change in timing.
*/
TransactionConfig txnConfig = new TransactionConfig();
runner.setTransactionConfig(txnConfig);
/*
* A thread to do put() and delete() via the primary, which will lock
* the primary first then the secondary. Uses transactions.
*/
final Thread thread1 = new Thread(new Runnable() {
public void run() {
try {
/* The TransactionRunner performs retries. */
for (int i = 0; i < N_ITERS; i +=1 ) {
runner.run(new TransactionWorker() {
public void doWork() throws Exception {
assertEquals(null, storeMap.put(N_ONE, N_101));
}
});
runner.run(new TransactionWorker() {
public void doWork() throws Exception {
assertEquals(N_101, storeMap.remove(N_ONE));
}
});
}
} catch (Exception e) {
e.printStackTrace();
exception = e;
}
}
}, "ThreadOne");
/*
* A thread to get() via the secondary, which will lock the secondary
* first then the primary. Does not use a transaction.
*/
final Thread thread2 = new Thread(new Runnable() {
public void run() {
try {
for (int i = 0; i < N_ITERS; i +=1 ) {
for (int j = 0; j < MAX_RETRIES; j += 1) {
try {
Object value = indexMap.get(N_ONE);
assertTrue(value == null ||
N_101.equals(value));
break;
} catch (Exception e) {
e = ExceptionUnwrapper.unwrap(e);
if (e instanceof DeadlockException) {
continue; /* Retry on deadlock. */
} else {
throw e;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
exception = e;
}
}
}, "ThreadTwo");
thread1.start();
thread2.start();
thread1.join();
thread2.join();
index.close();
index = null;
store.close();
store = null;
env.close();
env = null;
if (exception != null) {
fail(exception.toString());
}
}
}

View File

@@ -0,0 +1,33 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TestDataBinding.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import com.sleepycat.bind.EntryBinding;
import com.sleepycat.db.DatabaseEntry;
/**
* @author Mark Hayes
*/
class TestDataBinding implements EntryBinding {
public Object entryToObject(DatabaseEntry data) {
if (data.getSize() != 1) {
throw new IllegalStateException("size=" + data.getSize());
}
byte val = data.getData()[data.getOffset()];
return new Long(val);
}
public void objectToEntry(Object object, DatabaseEntry data) {
byte val = ((Number) object).byteValue();
data.setData(new byte[] { val }, 0, 1);
}
}

View File

@@ -0,0 +1,44 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TestEntity.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
/**
* @author Mark Hayes
*/
class TestEntity {
int key;
int value;
TestEntity(int key, int value) {
this.key = key;
this.value = value;
}
public boolean equals(Object o) {
try {
TestEntity e = (TestEntity) o;
return e.key == key && e.value == value;
} catch (ClassCastException e) {
return false;
}
}
public int hashCode() {
return key;
}
public String toString() {
return "[key " + key + " value " + value + ']';
}
}

View File

@@ -0,0 +1,63 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TestEntityBinding.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import com.sleepycat.bind.EntityBinding;
import com.sleepycat.bind.RecordNumberBinding;
import com.sleepycat.db.DatabaseEntry;
/**
* @author Mark Hayes
*/
class TestEntityBinding implements EntityBinding {
private boolean isRecNum;
TestEntityBinding(boolean isRecNum) {
this.isRecNum = isRecNum;
}
public Object entryToObject(DatabaseEntry key, DatabaseEntry value) {
byte keyByte;
if (isRecNum) {
if (key.getSize() != 4) {
throw new IllegalStateException();
}
keyByte = (byte) RecordNumberBinding.entryToRecordNumber(key);
} else {
if (key.getSize() != 1) {
throw new IllegalStateException();
}
keyByte = key.getData()[key.getOffset()];
}
if (value.getSize() != 1) {
throw new IllegalStateException();
}
byte valByte = value.getData()[value.getOffset()];
return new TestEntity(keyByte, valByte);
}
public void objectToKey(Object object, DatabaseEntry key) {
byte val = (byte) ((TestEntity) object).key;
if (isRecNum) {
RecordNumberBinding.recordNumberToEntry(val, key);
} else {
key.setData(new byte[] { val }, 0, 1);
}
}
public void objectToData(Object object, DatabaseEntry value) {
byte val = (byte) ((TestEntity) object).value;
value.setData(new byte[] { val }, 0, 1);
}
}

View File

@@ -0,0 +1,130 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TestEnv.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import java.io.File;
import java.io.IOException;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
import com.sleepycat.util.test.SharedTestUtils;
/**
* @author Mark Hayes
*/
public class TestEnv {
public static final TestEnv BDB;
public static final TestEnv CDB;
public static final TestEnv TXN;
static {
EnvironmentConfig config;
config = newEnvConfig();
BDB = new TestEnv("bdb", config);
if (DbCompat.CDB) {
config = newEnvConfig();
DbCompat.setInitializeCDB(config, true);
CDB = new TestEnv("cdb", config);
} else {
CDB = null;
}
config = newEnvConfig();
config.setTransactional(true);
DbCompat.setInitializeLocking(config, true);
TXN = new TestEnv("txn", config);
}
private static EnvironmentConfig newEnvConfig() {
EnvironmentConfig config = new EnvironmentConfig();
if (DbCompat.MEMORY_SUBSYSTEM) {
DbCompat.setInitializeCache(config, true);
}
return config;
}
public static final TestEnv[] ALL;
static {
if (DbCompat.CDB) {
ALL = new TestEnv[] { BDB, CDB, TXN };
} else {
ALL = new TestEnv[] { BDB, TXN };
}
}
private String name;
private EnvironmentConfig config;
TestEnv(String name, EnvironmentConfig config) {
this.name = name;
this.config = config;
}
public String getName() {
return name;
}
public boolean isTxnMode() {
return config.getTransactional();
}
public boolean isCdbMode() {
return DbCompat.getInitializeCDB(config);
}
public Environment open(String testName)
throws IOException, DatabaseException {
return open(testName, true);
}
public Environment open(String testName, boolean create)
throws IOException, DatabaseException {
config.setAllowCreate(create);
/* OLDEST deadlock detection on DB matches the use of timeouts on JE.*/
DbCompat.setLockDetectModeOldest(config);
File dir = getDirectory(testName, create);
return newEnvironment(dir, config);
}
/**
* Is overridden in XACollectionTest.
*/
protected Environment newEnvironment(File dir, EnvironmentConfig config)
throws DatabaseException, IOException {
return new Environment(dir, config);
}
public File getDirectory(String testName)
throws IOException {
return getDirectory(testName, true);
}
public File getDirectory(String testName, boolean create)
throws IOException {
if (create) {
return SharedTestUtils.getNewDir("db-test/" + testName);
} else {
return SharedTestUtils.getExistingDir("db-test/" + testName);
}
}
}

View File

@@ -0,0 +1,44 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TestKeyAssigner.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import com.sleepycat.bind.RecordNumberBinding;
import com.sleepycat.collections.PrimaryKeyAssigner;
import com.sleepycat.db.DatabaseEntry;
import com.sleepycat.db.DatabaseException;
/**
* @author Mark Hayes
*/
class TestKeyAssigner implements PrimaryKeyAssigner {
private byte next = 1;
private boolean isRecNum;
TestKeyAssigner(boolean isRecNum) {
this.isRecNum = isRecNum;
}
public void assignKey(DatabaseEntry keyData)
throws DatabaseException {
if (isRecNum) {
RecordNumberBinding.recordNumberToEntry(next, keyData);
} else {
keyData.setData(new byte[] { next }, 0, 1);
}
next += 1;
}
void reset() {
next = 1;
}
}

View File

@@ -0,0 +1,59 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TestKeyCreator.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import com.sleepycat.bind.RecordNumberBinding;
import com.sleepycat.db.DatabaseEntry;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.SecondaryDatabase;
import com.sleepycat.db.SecondaryKeyCreator;
/**
* Unused until secondaries are available.
* @author Mark Hayes
*/
class TestKeyCreator implements SecondaryKeyCreator {
private boolean isRecNum;
TestKeyCreator(boolean isRecNum) {
this.isRecNum = isRecNum;
}
public boolean createSecondaryKey(SecondaryDatabase db,
DatabaseEntry primaryKeyData,
DatabaseEntry valueData,
DatabaseEntry indexKeyData)
throws DatabaseException {
if (valueData.getSize() == 0) {
return false;
}
if (valueData.getSize() != 1) {
throw new IllegalStateException();
}
byte val = valueData.getData()[valueData.getOffset()];
if (val == 0) {
return false; // fixed-len pad value
}
val -= 100;
if (isRecNum) {
RecordNumberBinding.recordNumberToEntry(val, indexKeyData);
} else {
indexKeyData.setData(new byte[] { val }, 0, 1);
}
return true;
}
public void clearIndexKey(DatabaseEntry valueData) {
throw new RuntimeException("not supported");
}
}

View File

@@ -0,0 +1,121 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TestSR15721.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.collections.CurrentTransaction;
import com.sleepycat.db.Environment;
import com.sleepycat.util.test.TestEnv;
/**
* @author Chao Huang
*/
public class TestSR15721 extends TestCase {
/**
* Runs a command line collection test.
* @see #usage
*/
public static void main(String[] args)
throws Exception {
if (args.length == 1 &&
(args[0].equals("-h") || args[0].equals("-help"))) {
usage();
} else {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
}
private static void usage() {
System.out.println(
"Usage: java com.sleepycat.collections.test.TestSR15721"
+ " [-h | -help]\n");
System.exit(2);
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite(TestSR15721.class);
return suite;
}
private Environment env;
private CurrentTransaction currentTxn;
public void setUp()
throws Exception {
env = TestEnv.TXN.open("TestSR15721");
currentTxn = CurrentTransaction.getInstance(env);
}
public void tearDown() {
try {
if (env != null) {
env.close();
}
} catch (Exception e) {
System.out.println("Ignored exception during tearDown: " + e);
} finally {
/* Ensure that GC can cleanup. */
env = null;
currentTxn = null;
}
}
/**
* Tests that the CurrentTransaction instance doesn't indeed allow GC to
* reclaim while attached environment is open. [#15721]
*/
public void testSR15721Fix()
throws Exception {
int hash = currentTxn.hashCode();
int hash2 = -1;
currentTxn = CurrentTransaction.getInstance(env);
hash2 = currentTxn.hashCode();
assertTrue(hash == hash2);
currentTxn.beginTransaction(null);
currentTxn = null;
hash2 = -1;
for (int i = 0; i < 10; i += 1) {
byte[] x = null;
try {
x = new byte[Integer.MAX_VALUE - 1];
fail();
} catch (OutOfMemoryError expected) {
}
assertNull(x);
System.gc();
}
currentTxn = CurrentTransaction.getInstance(env);
hash2 = currentTxn.hashCode();
currentTxn.commitTransaction();
assertTrue(hash == hash2);
}
}

View File

@@ -0,0 +1,280 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TestStore.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.sleepycat.bind.EntityBinding;
import com.sleepycat.bind.EntryBinding;
import com.sleepycat.bind.RecordNumberBinding;
import com.sleepycat.collections.CurrentTransaction;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.SecondaryConfig;
/**
* @author Mark Hayes
*/
class TestStore {
static final TestKeyCreator BYTE_EXTRACTOR = new TestKeyCreator(false);
static final TestKeyCreator RECNO_EXTRACTOR = new TestKeyCreator(true);
static final EntryBinding VALUE_BINDING = new TestDataBinding();
static final EntryBinding BYTE_KEY_BINDING = VALUE_BINDING;
static final EntryBinding RECNO_KEY_BINDING = new RecordNumberBinding();
static final EntityBinding BYTE_ENTITY_BINDING =
new TestEntityBinding(false);
static final EntityBinding RECNO_ENTITY_BINDING =
new TestEntityBinding(true);
static final TestKeyAssigner BYTE_KEY_ASSIGNER =
new TestKeyAssigner(false);
static final TestKeyAssigner RECNO_KEY_ASSIGNER =
new TestKeyAssigner(true);
static final TestStore BTREE_UNIQ;
static final TestStore BTREE_DUP;
static final TestStore BTREE_DUPSORT;
static final TestStore BTREE_RECNUM;
static final TestStore HASH_UNIQ;
static final TestStore HASH_DUP;
static final TestStore HASH_DUPSORT;
static final TestStore QUEUE;
static final TestStore RECNO;
static final TestStore RECNO_RENUM;
static final TestStore[] ALL;
static {
List list = new ArrayList();
SecondaryConfig config;
config = new SecondaryConfig();
DbCompat.setTypeBtree(config);
BTREE_UNIQ = new TestStore("btree-uniq", config);
BTREE_UNIQ.indexOf = BTREE_UNIQ;
list.add(BTREE_UNIQ);
if (DbCompat.INSERTION_ORDERED_DUPLICATES) {
config = new SecondaryConfig();
DbCompat.setTypeBtree(config);
DbCompat.setUnsortedDuplicates(config, true);
BTREE_DUP = new TestStore("btree-dup", config);
BTREE_DUP.indexOf = null; // indexes must use sorted dups
list.add(BTREE_DUP);
} else {
BTREE_DUP = null;
}
config = new SecondaryConfig();
DbCompat.setTypeBtree(config);
DbCompat.setSortedDuplicates(config, true);
BTREE_DUPSORT = new TestStore("btree-dupsort", config);
BTREE_DUPSORT.indexOf = BTREE_UNIQ;
list.add(BTREE_DUPSORT);
if (DbCompat.BTREE_RECNUM_METHOD) {
config = new SecondaryConfig();
DbCompat.setTypeBtree(config);
DbCompat.setBtreeRecordNumbers(config, true);
BTREE_RECNUM = new TestStore("btree-recnum", config);
BTREE_RECNUM.indexOf = BTREE_RECNUM;
list.add(BTREE_RECNUM);
} else {
BTREE_RECNUM = null;
}
if (DbCompat.HASH_METHOD) {
config = new SecondaryConfig();
DbCompat.setTypeHash(config);
HASH_UNIQ = new TestStore("hash-uniq", config);
HASH_UNIQ.indexOf = HASH_UNIQ;
list.add(HASH_UNIQ);
if (DbCompat.INSERTION_ORDERED_DUPLICATES) {
config = new SecondaryConfig();
DbCompat.setTypeHash(config);
DbCompat.setUnsortedDuplicates(config, true);
HASH_DUP = new TestStore("hash-dup", config);
HASH_DUP.indexOf = null; // indexes must use sorted dups
list.add(HASH_DUP);
} else {
HASH_DUP = null;
}
config = new SecondaryConfig();
DbCompat.setTypeHash(config);
DbCompat.setSortedDuplicates(config, true);
HASH_DUPSORT = new TestStore("hash-dupsort", config);
HASH_DUPSORT.indexOf = HASH_UNIQ;
list.add(HASH_DUPSORT);
} else {
HASH_UNIQ = null;
HASH_DUP = null;
HASH_DUPSORT = null;
}
if (DbCompat.QUEUE_METHOD) {
config = new SecondaryConfig();
DbCompat.setTypeQueue(config);
QUEUE = new TestStore("queue", config);
QUEUE.indexOf = QUEUE;
list.add(QUEUE);
} else {
QUEUE = null;
}
if (DbCompat.RECNO_METHOD) {
config = new SecondaryConfig();
DbCompat.setTypeRecno(config);
RECNO = new TestStore("recno", config);
RECNO.indexOf = RECNO;
list.add(RECNO);
config = new SecondaryConfig();
DbCompat.setTypeRecno(config);
DbCompat.setRenumbering(config, true);
RECNO_RENUM = new TestStore("recno-renum", config);
RECNO_RENUM.indexOf = null; // indexes must have stable keys
list.add(RECNO_RENUM);
} else {
RECNO = null;
RECNO_RENUM = null;
}
ALL = new TestStore[list.size()];
list.toArray(ALL);
}
private String name;
private SecondaryConfig config;
private TestStore indexOf;
private boolean isRecNumFormat;
private TestStore(String name, SecondaryConfig config) {
this.name = name;
this.config = config;
isRecNumFormat = isQueueOrRecno() ||
(DbCompat.isTypeBtree(config) &&
DbCompat.getBtreeRecordNumbers(config));
}
EntryBinding getValueBinding() {
return VALUE_BINDING;
}
EntryBinding getKeyBinding() {
return isRecNumFormat ? RECNO_KEY_BINDING : BYTE_KEY_BINDING;
}
EntityBinding getEntityBinding() {
return isRecNumFormat ? RECNO_ENTITY_BINDING : BYTE_ENTITY_BINDING;
}
TestKeyAssigner getKeyAssigner() {
if (isQueueOrRecno()) {
return null;
} else {
if (isRecNumFormat) {
return RECNO_KEY_ASSIGNER;
} else {
return BYTE_KEY_ASSIGNER;
}
}
}
String getName() {
return name;
}
boolean isOrdered() {
return !DbCompat.isTypeHash(config);
}
boolean isQueueOrRecno() {
return DbCompat.isTypeQueue(config) || DbCompat.isTypeRecno(config);
}
boolean areKeyRangesAllowed() {
return isOrdered() && !isQueueOrRecno();
}
boolean areDuplicatesAllowed() {
return DbCompat.getSortedDuplicates(config) ||
DbCompat.getUnsortedDuplicates(config);
}
boolean hasRecNumAccess() {
return isRecNumFormat;
}
boolean areKeysRenumbered() {
return hasRecNumAccess() &&
(DbCompat.isTypeBtree(config) ||
DbCompat.getRenumbering(config));
}
TestStore getIndexOf() {
return DbCompat.SECONDARIES ? indexOf : null;
}
Database open(Environment env, String fileName)
throws IOException, DatabaseException {
int fixedLen = (isQueueOrRecno() ? 1 : 0);
return openDb(env, fileName, fixedLen, null);
}
Database openIndex(Database primary, String fileName)
throws IOException, DatabaseException {
int fixedLen = (isQueueOrRecno() ? 4 : 0);
config.setKeyCreator(isRecNumFormat ? RECNO_EXTRACTOR
: BYTE_EXTRACTOR);
Environment env = primary.getEnvironment();
return openDb(env, fileName, fixedLen, primary);
}
private Database openDb(Environment env, String fileName, int fixedLen,
Database primary)
throws IOException, DatabaseException {
if (fixedLen > 0) {
DbCompat.setRecordLength(config, fixedLen);
DbCompat.setRecordPad(config, 0);
} else {
DbCompat.setRecordLength(config, 0);
}
config.setAllowCreate(true);
DbCompat.setReadUncommitted(config, true);
config.setTransactional(CurrentTransaction.getInstance(env) != null);
if (primary != null) {
return DbCompat.testOpenSecondaryDatabase
(env, null, fileName, null, primary, config);
} else {
return DbCompat.testOpenDatabase
(env, null, fileName, null, config);
}
}
}

View File

@@ -0,0 +1,816 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TransactionTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.collections.CurrentTransaction;
import com.sleepycat.collections.StoredCollections;
import com.sleepycat.collections.StoredContainer;
import com.sleepycat.collections.StoredIterator;
import com.sleepycat.collections.StoredList;
import com.sleepycat.collections.StoredSortedMap;
import com.sleepycat.collections.TransactionRunner;
import com.sleepycat.collections.TransactionWorker;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.CursorConfig;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.DatabaseEntry;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
import com.sleepycat.db.Transaction;
import com.sleepycat.db.TransactionConfig;
import com.sleepycat.util.RuntimeExceptionWrapper;
import com.sleepycat.util.test.SharedTestUtils;
import com.sleepycat.util.test.TestEnv;
/**
* @author Mark Hayes
*/
public class TransactionTest extends TestCase {
private static final Long ONE = new Long(1);
private static final Long TWO = new Long(2);
private static final Long THREE = new Long(3);
/**
* Runs a command line collection test.
* @see #usage
*/
public static void main(String[] args)
throws Exception {
if (args.length == 1 &&
(args[0].equals("-h") || args[0].equals("-help"))) {
usage();
} else {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
}
private static void usage() {
System.out.println(
"Usage: java com.sleepycat.collections.test.TransactionTest"
+ " [-h | -help]\n");
System.exit(2);
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite(TransactionTest.class);
return suite;
}
private Environment env;
private CurrentTransaction currentTxn;
private Database store;
private StoredSortedMap map;
private TestStore testStore = TestStore.BTREE_UNIQ;
public TransactionTest(String name) {
super(name);
}
public void setUp()
throws Exception {
SharedTestUtils.printTestName(SharedTestUtils.qualifiedTestName(this));
env = TestEnv.TXN.open("TransactionTests");
currentTxn = CurrentTransaction.getInstance(env);
store = testStore.open(env, dbName(0));
map = new StoredSortedMap(store, testStore.getKeyBinding(),
testStore.getValueBinding(), true);
}
public void tearDown() {
try {
if (store != null) {
store.close();
}
if (env != null) {
env.close();
}
} catch (Exception e) {
System.out.println("Ignored exception during tearDown: " + e);
} finally {
/* Ensure that GC can cleanup. */
store = null;
env = null;
currentTxn = null;
map = null;
testStore = null;
}
}
private String dbName(int i) {
return "txn-test-" + getName() + '-' + i;
}
public void testGetters()
throws Exception {
assertNotNull(env);
assertNotNull(currentTxn);
assertNull(currentTxn.getTransaction());
currentTxn.beginTransaction(null);
assertNotNull(currentTxn.getTransaction());
currentTxn.commitTransaction();
assertNull(currentTxn.getTransaction());
currentTxn.beginTransaction(null);
assertNotNull(currentTxn.getTransaction());
currentTxn.abortTransaction();
assertNull(currentTxn.getTransaction());
// read-uncommitted property should be inherited
assertTrue(!isReadUncommitted(map));
assertTrue(!isReadUncommitted(map.values()));
assertTrue(!isReadUncommitted(map.keySet()));
assertTrue(!isReadUncommitted(map.entrySet()));
StoredSortedMap other = (StoredSortedMap)
StoredCollections.configuredMap
(map, CursorConfig.READ_UNCOMMITTED);
assertTrue(isReadUncommitted(other));
assertTrue(isReadUncommitted(other.values()));
assertTrue(isReadUncommitted(other.keySet()));
assertTrue(isReadUncommitted(other.entrySet()));
assertTrue(!isReadUncommitted(map));
assertTrue(!isReadUncommitted(map.values()));
assertTrue(!isReadUncommitted(map.keySet()));
assertTrue(!isReadUncommitted(map.entrySet()));
// read-committed property should be inherited
assertTrue(!isReadCommitted(map));
assertTrue(!isReadCommitted(map.values()));
assertTrue(!isReadCommitted(map.keySet()));
assertTrue(!isReadCommitted(map.entrySet()));
other = (StoredSortedMap)
StoredCollections.configuredMap
(map, CursorConfig.READ_COMMITTED);
assertTrue(isReadCommitted(other));
assertTrue(isReadCommitted(other.values()));
assertTrue(isReadCommitted(other.keySet()));
assertTrue(isReadCommitted(other.entrySet()));
assertTrue(!isReadCommitted(map));
assertTrue(!isReadCommitted(map.values()));
assertTrue(!isReadCommitted(map.keySet()));
assertTrue(!isReadCommitted(map.entrySet()));
}
public void testTransactional()
throws Exception {
// is transactional because DB_AUTO_COMMIT was passed to
// Database.open()
//
assertTrue(map.isTransactional());
store.close();
store = null;
// is not transactional
//
DatabaseConfig dbConfig = new DatabaseConfig();
DbCompat.setTypeBtree(dbConfig);
dbConfig.setAllowCreate(true);
Database db = DbCompat.testOpenDatabase
(env, null, dbName(1), null, dbConfig);
map = new StoredSortedMap(db, testStore.getKeyBinding(),
testStore.getValueBinding(), true);
assertTrue(!map.isTransactional());
map.put(ONE, ONE);
readCheck(map, ONE, ONE);
db.close();
// is transactional
//
dbConfig.setTransactional(true);
currentTxn.beginTransaction(null);
db = DbCompat.testOpenDatabase
(env, currentTxn.getTransaction(), dbName(2), null, dbConfig);
currentTxn.commitTransaction();
map = new StoredSortedMap(db, testStore.getKeyBinding(),
testStore.getValueBinding(), true);
assertTrue(map.isTransactional());
currentTxn.beginTransaction(null);
map.put(ONE, ONE);
readCheck(map, ONE, ONE);
currentTxn.commitTransaction();
db.close();
}
public void testExceptions()
throws Exception {
try {
currentTxn.commitTransaction();
fail();
} catch (IllegalStateException expected) {}
try {
currentTxn.abortTransaction();
fail();
} catch (IllegalStateException expected) {}
}
public void testNested()
throws Exception {
if (!DbCompat.NESTED_TRANSACTIONS) {
return;
}
assertNull(currentTxn.getTransaction());
Transaction txn1 = currentTxn.beginTransaction(null);
assertNotNull(txn1);
assertTrue(txn1 == currentTxn.getTransaction());
assertNull(map.get(ONE));
assertNull(map.put(ONE, ONE));
assertEquals(ONE, map.get(ONE));
Transaction txn2 = currentTxn.beginTransaction(null);
assertNotNull(txn2);
assertTrue(txn2 == currentTxn.getTransaction());
assertTrue(txn1 != txn2);
assertNull(map.put(TWO, TWO));
assertEquals(TWO, map.get(TWO));
Transaction txn3 = currentTxn.beginTransaction(null);
assertNotNull(txn3);
assertTrue(txn3 == currentTxn.getTransaction());
assertTrue(txn1 != txn2);
assertTrue(txn1 != txn3);
assertTrue(txn2 != txn3);
assertNull(map.put(THREE, THREE));
assertEquals(THREE, map.get(THREE));
Transaction txn = currentTxn.abortTransaction();
assertTrue(txn == txn2);
assertTrue(txn == currentTxn.getTransaction());
assertNull(map.get(THREE));
assertEquals(TWO, map.get(TWO));
txn3 = currentTxn.beginTransaction(null);
assertNotNull(txn3);
assertTrue(txn3 == currentTxn.getTransaction());
assertTrue(txn1 != txn2);
assertTrue(txn1 != txn3);
assertTrue(txn2 != txn3);
assertNull(map.put(THREE, THREE));
assertEquals(THREE, map.get(THREE));
txn = currentTxn.commitTransaction();
assertTrue(txn == txn2);
assertTrue(txn == currentTxn.getTransaction());
assertEquals(THREE, map.get(THREE));
assertEquals(TWO, map.get(TWO));
txn = currentTxn.commitTransaction();
assertTrue(txn == txn1);
assertTrue(txn == currentTxn.getTransaction());
assertEquals(THREE, map.get(THREE));
assertEquals(TWO, map.get(TWO));
assertEquals(ONE, map.get(ONE));
txn = currentTxn.commitTransaction();
assertNull(txn);
assertNull(currentTxn.getTransaction());
assertEquals(THREE, map.get(THREE));
assertEquals(TWO, map.get(TWO));
assertEquals(ONE, map.get(ONE));
}
public void testRunnerCommit()
throws Exception {
commitTest(false);
}
public void testExplicitCommit()
throws Exception {
commitTest(true);
}
private void commitTest(final boolean explicit)
throws Exception {
final TransactionRunner runner = new TransactionRunner(env);
runner.setAllowNestedTransactions(DbCompat.NESTED_TRANSACTIONS);
assertNull(currentTxn.getTransaction());
runner.run(new TransactionWorker() {
public void doWork() throws Exception {
final Transaction txn1 = currentTxn.getTransaction();
assertNotNull(txn1);
assertNull(map.put(ONE, ONE));
assertEquals(ONE, map.get(ONE));
runner.run(new TransactionWorker() {
public void doWork() throws Exception {
final Transaction txn2 = currentTxn.getTransaction();
assertNotNull(txn2);
if (DbCompat.NESTED_TRANSACTIONS) {
assertTrue(txn1 != txn2);
} else {
assertTrue(txn1 == txn2);
}
assertNull(map.put(TWO, TWO));
assertEquals(TWO, map.get(TWO));
assertEquals(ONE, map.get(ONE));
if (DbCompat.NESTED_TRANSACTIONS && explicit) {
currentTxn.commitTransaction();
}
}
});
Transaction txn3 = currentTxn.getTransaction();
assertSame(txn1, txn3);
assertEquals(TWO, map.get(TWO));
assertEquals(ONE, map.get(ONE));
}
});
assertNull(currentTxn.getTransaction());
}
public void testRunnerAbort()
throws Exception {
abortTest(false);
}
public void testExplicitAbort()
throws Exception {
abortTest(true);
}
private void abortTest(final boolean explicit)
throws Exception {
final TransactionRunner runner = new TransactionRunner(env);
runner.setAllowNestedTransactions(DbCompat.NESTED_TRANSACTIONS);
assertNull(currentTxn.getTransaction());
runner.run(new TransactionWorker() {
public void doWork() throws Exception {
final Transaction txn1 = currentTxn.getTransaction();
assertNotNull(txn1);
assertNull(map.put(ONE, ONE));
assertEquals(ONE, map.get(ONE));
if (DbCompat.NESTED_TRANSACTIONS) {
try {
runner.run(new TransactionWorker() {
public void doWork() throws Exception {
final Transaction txn2 =
currentTxn.getTransaction();
assertNotNull(txn2);
assertTrue(txn1 != txn2);
assertNull(map.put(TWO, TWO));
assertEquals(TWO, map.get(TWO));
if (explicit) {
currentTxn.abortTransaction();
} else {
throw new IllegalArgumentException(
"test-abort");
}
}
});
assertTrue(explicit);
} catch (IllegalArgumentException e) {
assertTrue(!explicit);
assertEquals("test-abort", e.getMessage());
}
}
Transaction txn3 = currentTxn.getTransaction();
assertSame(txn1, txn3);
assertEquals(ONE, map.get(ONE));
assertNull(map.get(TWO));
}
});
assertNull(currentTxn.getTransaction());
}
public void testReadCommittedCollection()
throws Exception {
StoredSortedMap degree2Map = (StoredSortedMap)
StoredCollections.configuredSortedMap
(map, CursorConfig.READ_COMMITTED);
// original map is not read-committed
assertTrue(!isReadCommitted(map));
// all read-committed containers are read-uncommitted
assertTrue(isReadCommitted(degree2Map));
assertTrue(isReadCommitted
(StoredCollections.configuredMap
(map, CursorConfig.READ_COMMITTED)));
assertTrue(isReadCommitted
(StoredCollections.configuredCollection
(map.values(), CursorConfig.READ_COMMITTED)));
assertTrue(isReadCommitted
(StoredCollections.configuredSet
(map.keySet(), CursorConfig.READ_COMMITTED)));
assertTrue(isReadCommitted
(StoredCollections.configuredSortedSet
((SortedSet) map.keySet(),
CursorConfig.READ_COMMITTED)));
if (DbCompat.RECNO_METHOD) {
// create a list just so we can call configuredList()
Database listStore = TestStore.RECNO_RENUM.open(env, null);
List list = new StoredList(listStore, TestStore.VALUE_BINDING,
true);
assertTrue(isReadCommitted
(StoredCollections.configuredList
(list, CursorConfig.READ_COMMITTED)));
listStore.close();
}
map.put(ONE, ONE);
doReadCommitted(degree2Map, null);
}
private static boolean isReadCommitted(Object container) {
StoredContainer storedContainer = (StoredContainer) container;
/* We can't use getReadCommitted until is is added to DB core. */
return storedContainer.getCursorConfig() != null &&
storedContainer.getCursorConfig().getReadCommitted();
}
public void testReadCommittedTransaction()
throws Exception {
TransactionConfig config = new TransactionConfig();
config.setReadCommitted(true);
doReadCommitted(map, config);
}
private void doReadCommitted(final StoredSortedMap degree2Map,
TransactionConfig txnConfig)
throws Exception {
map.put(ONE, ONE);
TransactionRunner runner = new TransactionRunner(env);
runner.setTransactionConfig(txnConfig);
assertNull(currentTxn.getTransaction());
runner.run(new TransactionWorker() {
public void doWork() throws Exception {
assertNotNull(currentTxn.getTransaction());
/* Do a read-committed get(), the lock is not retained. */
assertEquals(ONE, degree2Map.get(ONE));
/*
* If we were not using read-committed, the following write of
* key ONE with an auto-commit transaction would self-deadlock
* since two transactions in the same thread would be
* attempting to lock the same key, one for write and one for
* read. This test passes if we do not deadlock.
*/
DatabaseEntry key = new DatabaseEntry();
DatabaseEntry value = new DatabaseEntry();
testStore.getKeyBinding().objectToEntry(ONE, key);
testStore.getValueBinding().objectToEntry(TWO, value);
store.put(null, key, value);
}
});
assertNull(currentTxn.getTransaction());
}
public void testReadUncommittedCollection()
throws Exception {
StoredSortedMap dirtyMap = (StoredSortedMap)
StoredCollections.configuredSortedMap
(map, CursorConfig.READ_UNCOMMITTED);
// original map is not read-uncommitted
assertTrue(!isReadUncommitted(map));
// all read-uncommitted containers are read-uncommitted
assertTrue(isReadUncommitted(dirtyMap));
assertTrue(isReadUncommitted
(StoredCollections.configuredMap
(map, CursorConfig.READ_UNCOMMITTED)));
assertTrue(isReadUncommitted
(StoredCollections.configuredCollection
(map.values(), CursorConfig.READ_UNCOMMITTED)));
assertTrue(isReadUncommitted
(StoredCollections.configuredSet
(map.keySet(), CursorConfig.READ_UNCOMMITTED)));
assertTrue(isReadUncommitted
(StoredCollections.configuredSortedSet
((SortedSet) map.keySet(), CursorConfig.READ_UNCOMMITTED)));
if (DbCompat.RECNO_METHOD) {
// create a list just so we can call configuredList()
Database listStore = TestStore.RECNO_RENUM.open(env, null);
List list = new StoredList(listStore, TestStore.VALUE_BINDING,
true);
assertTrue(isReadUncommitted
(StoredCollections.configuredList
(list, CursorConfig.READ_UNCOMMITTED)));
listStore.close();
}
doReadUncommitted(dirtyMap);
}
private static boolean isReadUncommitted(Object container) {
StoredContainer storedContainer = (StoredContainer) container;
return storedContainer.getCursorConfig() != null &&
storedContainer.getCursorConfig().getReadUncommitted();
}
public void testReadUncommittedTransaction()
throws Exception {
TransactionRunner runner = new TransactionRunner(env);
TransactionConfig config = new TransactionConfig();
config.setReadUncommitted(true);
runner.setTransactionConfig(config);
assertNull(currentTxn.getTransaction());
runner.run(new TransactionWorker() {
public void doWork() throws Exception {
assertNotNull(currentTxn.getTransaction());
doReadUncommitted(map);
}
});
assertNull(currentTxn.getTransaction());
}
/**
* Tests that the CurrentTransaction static WeakHashMap does indeed allow
* GC to reclaim tine environment when it is closed. At one point this was
* not working because the value object in the map has a reference to the
* environment. This was fixed by wrapping the Environment in a
* WeakReference. [#15444]
*
* This test only succeeds intermittently, probably due to its reliance
* on the GC call.
*/
public void testCurrentTransactionGC()
throws Exception {
/*
* This test can have indeterminate results because it depends on
* a finalize count, so it's not part of the default run.
*/
if (!SharedTestUtils.runLongTests()) {
return;
}
final StringBuffer finalizedFlag = new StringBuffer();
class MyEnv extends Environment {
MyEnv(File home, EnvironmentConfig config)
throws IOException, DatabaseException {
super(home, config);
}
protected void finalize() {
finalizedFlag.append('.');
}
}
MyEnv myEnv = new MyEnv(env.getHome(), env.getConfig());
CurrentTransaction myCurrTxn = CurrentTransaction.getInstance(myEnv);
store.close();
store = null;
map = null;
env.close();
env = null;
myEnv.close();
myEnv = null;
myCurrTxn = null;
currentTxn = null;
for (int i = 0; i < 10; i += 1) {
byte[] x = null;
try {
x = new byte[Integer.MAX_VALUE - 1];
} catch (OutOfMemoryError expected) {
}
assertNull(x);
System.gc();
}
for (int i = 0; i < 10; i += 1) {
System.gc();
}
assertTrue(finalizedFlag.length() > 0);
}
private synchronized void doReadUncommitted(StoredSortedMap dirtyMap)
throws Exception {
// start thread one
ReadUncommittedThreadOne t1 = new ReadUncommittedThreadOne(env, this);
t1.start();
wait();
// put ONE
synchronized (t1) { t1.notify(); }
wait();
readCheck(dirtyMap, ONE, ONE);
assertTrue(!dirtyMap.isEmpty());
// abort ONE
synchronized (t1) { t1.notify(); }
t1.join();
readCheck(dirtyMap, ONE, null);
assertTrue(dirtyMap.isEmpty());
// start thread two
ReadUncommittedThreadTwo t2 = new ReadUncommittedThreadTwo(env, this);
t2.start();
wait();
// put TWO
synchronized (t2) { t2.notify(); }
wait();
readCheck(dirtyMap, TWO, TWO);
assertTrue(!dirtyMap.isEmpty());
// commit TWO
synchronized (t2) { t2.notify(); }
t2.join();
readCheck(dirtyMap, TWO, TWO);
assertTrue(!dirtyMap.isEmpty());
}
private static class ReadUncommittedThreadOne extends Thread {
private CurrentTransaction currentTxn;
private TransactionTest parent;
private StoredSortedMap map;
private ReadUncommittedThreadOne(Environment env,
TransactionTest parent) {
this.currentTxn = CurrentTransaction.getInstance(env);
this.parent = parent;
this.map = parent.map;
}
public synchronized void run() {
try {
assertNull(currentTxn.getTransaction());
assertNotNull(currentTxn.beginTransaction(null));
assertNotNull(currentTxn.getTransaction());
readCheck(map, ONE, null);
synchronized (parent) { parent.notify(); }
wait();
// put ONE
assertNull(map.put(ONE, ONE));
readCheck(map, ONE, ONE);
synchronized (parent) { parent.notify(); }
wait();
// abort ONE
assertNull(currentTxn.abortTransaction());
assertNull(currentTxn.getTransaction());
} catch (Exception e) {
throw new RuntimeExceptionWrapper(e);
}
}
}
private static class ReadUncommittedThreadTwo extends Thread {
private Environment env;
private CurrentTransaction currentTxn;
private TransactionTest parent;
private StoredSortedMap map;
private ReadUncommittedThreadTwo(Environment env,
TransactionTest parent) {
this.env = env;
this.currentTxn = CurrentTransaction.getInstance(env);
this.parent = parent;
this.map = parent.map;
}
public synchronized void run() {
try {
final TransactionRunner runner = new TransactionRunner(env);
final Object thread = this;
assertNull(currentTxn.getTransaction());
runner.run(new TransactionWorker() {
public void doWork() throws Exception {
assertNotNull(currentTxn.getTransaction());
readCheck(map, TWO, null);
synchronized (parent) { parent.notify(); }
thread.wait();
// put TWO
assertNull(map.put(TWO, TWO));
readCheck(map, TWO, TWO);
synchronized (parent) { parent.notify(); }
thread.wait();
// commit TWO
}
});
assertNull(currentTxn.getTransaction());
} catch (Exception e) {
throw new RuntimeExceptionWrapper(e);
}
}
}
private static void readCheck(StoredSortedMap checkMap, Object key,
Object expect) {
if (expect == null) {
assertNull(checkMap.get(key));
assertTrue(checkMap.tailMap(key).isEmpty());
assertTrue(!checkMap.tailMap(key).containsKey(key));
assertTrue(!checkMap.keySet().contains(key));
assertTrue(checkMap.duplicates(key).isEmpty());
Iterator i = checkMap.keySet().iterator();
try {
while (i.hasNext()) {
assertTrue(!key.equals(i.next()));
}
} finally { StoredIterator.close(i); }
} else {
assertEquals(expect, checkMap.get(key));
assertEquals(expect, checkMap.tailMap(key).get(key));
assertTrue(!checkMap.tailMap(key).isEmpty());
assertTrue(checkMap.tailMap(key).containsKey(key));
assertTrue(checkMap.keySet().contains(key));
assertTrue(checkMap.values().contains(expect));
assertTrue(!checkMap.duplicates(key).isEmpty());
assertTrue(checkMap.duplicates(key).contains(expect));
Iterator i = checkMap.keySet().iterator();
try {
boolean found = false;
while (i.hasNext()) {
if (expect.equals(i.next())) {
found = true;
}
}
assertTrue(found);
}
finally { StoredIterator.close(i); }
}
}
}

View File

@@ -0,0 +1,99 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: CatalogCornerCaseTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test.serial;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.bind.serial.StoredClassCatalog;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.Environment;
import com.sleepycat.util.test.SharedTestUtils;
import com.sleepycat.util.test.TestEnv;
/**
* @author Mark Hayes
*/
public class CatalogCornerCaseTest extends TestCase {
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
return new TestSuite(CatalogCornerCaseTest.class);
}
private Environment env;
public CatalogCornerCaseTest(String name) {
super(name);
}
public void setUp()
throws Exception {
SharedTestUtils.printTestName(getName());
env = TestEnv.BDB.open(getName());
}
public void tearDown() {
try {
if (env != null) {
env.close();
}
} catch (Exception e) {
System.out.println("Ignored exception during tearDown: " + e);
} finally {
/* Ensure that GC can cleanup. */
env = null;
}
}
public void testReadOnlyEmptyCatalog()
throws Exception {
String file = "catalog.db";
/* Create an empty database. */
DatabaseConfig config = new DatabaseConfig();
config.setAllowCreate(true);
DbCompat.setTypeBtree(config);
Database db =
DbCompat.testOpenDatabase(env, null, file, null, config);
db.close();
/* Open the empty database read-only. */
config.setAllowCreate(false);
config.setReadOnly(true);
db = DbCompat.testOpenDatabase(env, null, file, null, config);
/* Expect exception when creating the catalog. */
try {
new StoredClassCatalog(db);
fail();
} catch (IllegalStateException e) { }
db.close();
}
}

View File

@@ -0,0 +1,178 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: StoredClassCatalogTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test.serial;
import java.io.ObjectStreamClass;
import java.util.Map;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.bind.serial.SerialBinding;
import com.sleepycat.bind.serial.StoredClassCatalog;
import com.sleepycat.collections.StoredMap;
import com.sleepycat.collections.TransactionRunner;
import com.sleepycat.collections.TransactionWorker;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.Environment;
import com.sleepycat.util.test.SharedTestUtils;
import com.sleepycat.util.test.TestEnv;
/**
* Runs part two of the StoredClassCatalogTest. This part is run with the
* new/updated version of TestSerial in the classpath. It uses the
* environment and databases created by StoredClassCatalogTestInit. It
* verifies that it can read objects serialized using the old class format,
* and that it can create new objects with the new class format.
*
* @author Mark Hayes
*/
public class StoredClassCatalogTest extends TestCase
implements TransactionWorker {
static final String CATALOG_FILE = "catalogtest-catalog.db";
static final String STORE_FILE = "catalogtest-store.db";
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite();
for (int i = 0; i < TestEnv.ALL.length; i += 1) {
suite.addTest(new StoredClassCatalogTest(TestEnv.ALL[i]));
}
return suite;
}
private TestEnv testEnv;
private Environment env;
private StoredClassCatalog catalog;
private StoredClassCatalog catalog2;
private Database store;
private Map map;
private TransactionRunner runner;
public StoredClassCatalogTest(TestEnv testEnv) {
super(makeTestName(testEnv));
this.testEnv = testEnv;
}
static String makeTestName(TestEnv testEnv) {
return "StoredClassCatalogTest-" + testEnv.getName();
}
public void setUp()
throws Exception {
SharedTestUtils.printTestName(getName());
env = testEnv.open(makeTestName(testEnv), false);
runner = new TransactionRunner(env);
catalog = new StoredClassCatalog(openDb(CATALOG_FILE, false));
catalog2 = new StoredClassCatalog(openDb("catalog2.db", true));
SerialBinding keyBinding = new SerialBinding(catalog,
String.class);
SerialBinding valueBinding = new SerialBinding(catalog,
TestSerial.class);
store = openDb(STORE_FILE, false);
map = new StoredMap(store, keyBinding, valueBinding, true);
}
private Database openDb(String file, boolean create)
throws Exception {
DatabaseConfig config = new DatabaseConfig();
DbCompat.setTypeBtree(config);
config.setTransactional(testEnv.isTxnMode());
config.setAllowCreate(create);
return DbCompat.testOpenDatabase(env, null, file, null, config);
}
public void tearDown() {
try {
if (catalog != null) {
catalog.close();
catalog.close(); // should have no effect
}
if (catalog2 != null) {
catalog2.close();
}
if (store != null) {
store.close();
}
if (env != null) {
env.close();
}
} catch (Exception e) {
System.err.println("Ignored exception during tearDown: ");
e.printStackTrace();
} finally {
/* Ensure that GC can cleanup. */
catalog = null;
catalog2 = null;
store = null;
env = null;
testEnv = null;
map = null;
runner = null;
}
}
public void runTest()
throws Exception {
runner.run(this);
}
public void doWork()
throws Exception {
TestSerial one = (TestSerial) map.get("one");
TestSerial two = (TestSerial) map.get("two");
assertNotNull(one);
assertNotNull(two);
assertEquals(one, two.getOther());
assertNull(one.getStringField());
assertNull(two.getStringField());
TestSerial three = new TestSerial(two);
assertNotNull(three.getStringField());
map.put("three", three);
three = (TestSerial) map.get("three");
assertEquals(two, three.getOther());
ObjectStreamClass desc = ObjectStreamClass.lookup(TestSerial.class);
assertNotNull(catalog.getClassID(desc));
assertNotNull(catalog.getClassID(desc));
// test with empty catalog
assertNotNull(catalog2.getClassID(desc));
assertNotNull(catalog2.getClassID(desc));
}
}

View File

@@ -0,0 +1,157 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: StoredClassCatalogTestInit.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test.serial;
import java.util.Map;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.bind.serial.SerialBinding;
import com.sleepycat.bind.serial.StoredClassCatalog;
import com.sleepycat.collections.StoredMap;
import com.sleepycat.collections.TransactionRunner;
import com.sleepycat.collections.TransactionWorker;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.Environment;
import com.sleepycat.util.test.SharedTestUtils;
import com.sleepycat.util.test.TestEnv;
/**
* Runs part one of the StoredClassCatalogTest. This part is run with the
* old/original version of TestSerial in the classpath. It creates a fresh
* environment and databases containing serialized versions of the old class.
* When StoredClassCatalogTest is run, it will read these objects from the
* database created here.
*
* @author Mark Hayes
*/
public class StoredClassCatalogTestInit extends TestCase
implements TransactionWorker {
static final String CATALOG_FILE = StoredClassCatalogTest.CATALOG_FILE;
static final String STORE_FILE = StoredClassCatalogTest.STORE_FILE;
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite();
for (int i = 0; i < TestEnv.ALL.length; i += 1) {
suite.addTest(new StoredClassCatalogTestInit(TestEnv.ALL[i]));
}
return suite;
}
private TestEnv testEnv;
private Environment env;
private StoredClassCatalog catalog;
private Database store;
private Map map;
private TransactionRunner runner;
public StoredClassCatalogTestInit(TestEnv testEnv) {
super("StoredClassCatalogTestInit-" + testEnv.getName());
this.testEnv = testEnv;
}
public void setUp()
throws Exception {
SharedTestUtils.printTestName(getName());
env = testEnv.open(StoredClassCatalogTest.makeTestName(testEnv));
runner = new TransactionRunner(env);
catalog = new StoredClassCatalog(openDb(CATALOG_FILE));
SerialBinding keyBinding = new SerialBinding(catalog, String.class);
SerialBinding valueBinding =
new SerialBinding(catalog, TestSerial.class);
store = openDb(STORE_FILE);
map = new StoredMap(store, keyBinding, valueBinding, true);
}
private Database openDb(String file)
throws Exception {
DatabaseConfig config = new DatabaseConfig();
DbCompat.setTypeBtree(config);
config.setTransactional(testEnv.isTxnMode());
config.setAllowCreate(true);
return DbCompat.testOpenDatabase(env, null, file, null, config);
}
public void tearDown() {
try {
if (catalog != null) {
catalog.close();
catalog.close(); // should have no effect
}
if (store != null) {
store.close();
}
if (env != null) {
env.close();
}
} catch (Exception e) {
System.err.println("Ignored exception during tearDown: ");
e.printStackTrace();
} finally {
/* Ensure that GC can cleanup. */
catalog = null;
store = null;
env = null;
testEnv = null;
map = null;
runner = null;
}
}
public void runTest()
throws Exception {
runner.run(this);
}
public void doWork()
throws Exception {
TestSerial one = new TestSerial(null);
TestSerial two = new TestSerial(one);
assertNull("Likely the classpath contains the wrong version of the" +
" TestSerial class, the 'original' version is required",
one.getStringField());
assertNull(two.getStringField());
map.put("one", one);
map.put("two", two);
one = (TestSerial) map.get("one");
two = (TestSerial) map.get("two");
assertEquals(one, two.getOther());
assertNull(one.getStringField());
assertNull(two.getStringField());
}
}

View File

@@ -0,0 +1,70 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: TestSerial.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test.serial;
/**
* @see StoredClassCatalogTest
* @author Mark Hayes
*/
class TestSerial implements java.io.Serializable {
static final long serialVersionUID = -3738980000390384920L;
private int i = 123;
private TestSerial other;
// The following field 's' was added after this class was compiled and
// serialized instances were saved in resource files. This allows testing
// that the original stored instances can be deserialized after changing
// the class. The serialVersionUID is needed for this according to Java
// serialization rules, and was generated with the serialver tool.
//
private String s = "string";
TestSerial(TestSerial other) {
this.other = other;
}
TestSerial getOther() {
return other;
}
int getIntField() {
return i;
}
String getStringField() {
return s; // this returned null before field 's' was added.
}
public boolean equals(Object object) {
try {
TestSerial o = (TestSerial) object;
if ((o.other == null) ? (this.other != null)
: (!o.other.equals(this.other))) {
return false;
}
if (this.i != o.i) {
return false;
}
// the following test was not done before field 's' was added
if ((o.s == null) ? (this.s != null)
: (!o.s.equals(this.s))) {
return false;
}
return true;
} catch (ClassCastException e) {
return false;
}
}
}

View File

@@ -0,0 +1,72 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: TestSerial.java.original,v 12.10 2008/02/07 17:12:32 mark Exp $
*/
package com.sleepycat.collections.test.serial;
/**
* @see StoredClassCatalogTest
* @author Mark Hayes
*/
class TestSerial implements java.io.Serializable
{
static final long serialVersionUID = -3738980000390384920L;
private int i = 123;
private TestSerial other;
// The following field 's' was added after this class was compiled and
// serialized instances were saved in resource files. This allows testing
// that the original stored instances can be deserialized after changing
// the class. The serialVersionUID is needed for this according to Java
// serialization rules, and was generated with the serialver tool.
//
//private String s = "string";
TestSerial(TestSerial other)
{
this.other = other;
}
TestSerial getOther()
{
return other;
}
int getIntField()
{
return i;
}
String getStringField()
{
return null; // this returned null before field 's' was added.
}
public boolean equals(Object object)
{
try
{
TestSerial o = (TestSerial) object;
if ((o.other == null) ? (this.other != null)
: (!o.other.equals(this.other)))
return false;
if (this.i != o.i)
return false;
// the following test was not done before field 's' was added
/*
if ((o.s == null) ? (this.s != null)
: (!o.s.equals(this.s)))
return false;
*/
return true;
}
catch (ClassCastException e)
{
return false;
}
}
}

View File

@@ -0,0 +1,252 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: TupleSerialFactoryTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.collections.test.serial;
import java.util.Map;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.bind.serial.StoredClassCatalog;
import com.sleepycat.bind.serial.test.MarshalledObject;
import com.sleepycat.collections.TransactionRunner;
import com.sleepycat.collections.TransactionWorker;
import com.sleepycat.collections.TupleSerialFactory;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.Environment;
import com.sleepycat.db.ForeignKeyDeleteAction;
import com.sleepycat.db.SecondaryConfig;
import com.sleepycat.db.SecondaryDatabase;
import com.sleepycat.util.test.SharedTestUtils;
import com.sleepycat.util.test.TestEnv;
/**
* @author Mark Hayes
*/
public class TupleSerialFactoryTest extends TestCase
implements TransactionWorker {
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite();
for (int i = 0; i < TestEnv.ALL.length; i += 1) {
for (int sorted = 0; sorted < 2; sorted += 1) {
suite.addTest(new TupleSerialFactoryTest(TestEnv.ALL[i],
sorted != 0));
}
}
return suite;
}
private TestEnv testEnv;
private Environment env;
private StoredClassCatalog catalog;
private TransactionRunner runner;
private TupleSerialFactory factory;
private Database store1;
private Database store2;
private SecondaryDatabase index1;
private SecondaryDatabase index2;
private boolean isSorted;
private Map storeMap1;
private Map storeMap2;
private Map indexMap1;
private Map indexMap2;
public TupleSerialFactoryTest(TestEnv testEnv, boolean isSorted) {
super(null);
this.testEnv = testEnv;
this.isSorted = isSorted;
String name = "TupleSerialFactoryTest-" + testEnv.getName();
name += isSorted ? "-sorted" : "-unsorted";
setName(name);
}
public void setUp()
throws Exception {
SharedTestUtils.printTestName(getName());
env = testEnv.open(getName());
runner = new TransactionRunner(env);
createDatabase();
}
public void tearDown() {
try {
if (index1 != null) {
index1.close();
}
if (index2 != null) {
index2.close();
}
if (store1 != null) {
store1.close();
}
if (store2 != null) {
store2.close();
}
if (catalog != null) {
catalog.close();
}
if (env != null) {
env.close();
}
} catch (Exception e) {
System.out.println("Ignored exception during tearDown: " + e);
} finally {
/* Ensure that GC can cleanup. */
index1 = null;
index2 = null;
store1 = null;
store2 = null;
catalog = null;
env = null;
testEnv = null;
runner = null;
factory = null;
storeMap1 = null;
storeMap2 = null;
indexMap1 = null;
indexMap2 = null;
}
}
public void runTest()
throws Exception {
runner.run(this);
}
public void doWork()
throws Exception {
createViews();
writeAndRead();
}
private void createDatabase()
throws Exception {
catalog = new StoredClassCatalog(openDb("catalog.db"));
factory = new TupleSerialFactory(catalog);
assertSame(catalog, factory.getCatalog());
store1 = openDb("store1.db");
store2 = openDb("store2.db");
index1 = openSecondaryDb(factory, "1", store1, "index1.db", null);
index2 = openSecondaryDb(factory, "2", store2, "index2.db", store1);
}
private Database openDb(String file)
throws Exception {
DatabaseConfig config = new DatabaseConfig();
config.setTransactional(testEnv.isTxnMode());
config.setAllowCreate(true);
DbCompat.setTypeBtree(config);
return DbCompat.testOpenDatabase(env, null, file, null, config);
}
private SecondaryDatabase openSecondaryDb(TupleSerialFactory factory,
String keyName,
Database primary,
String file,
Database foreignStore)
throws Exception {
SecondaryConfig secConfig = new SecondaryConfig();
secConfig.setTransactional(testEnv.isTxnMode());
secConfig.setAllowCreate(true);
DbCompat.setTypeBtree(secConfig);
secConfig.setKeyCreator(factory.getKeyCreator(MarshalledObject.class,
keyName));
if (foreignStore != null) {
secConfig.setForeignKeyDatabase(foreignStore);
secConfig.setForeignKeyDeleteAction(
ForeignKeyDeleteAction.CASCADE);
}
return DbCompat.testOpenSecondaryDatabase
(env, null, file, null, primary, secConfig);
}
private void createViews()
throws Exception {
if (isSorted) {
storeMap1 = factory.newSortedMap(store1, String.class,
MarshalledObject.class, true);
storeMap2 = factory.newSortedMap(store2, String.class,
MarshalledObject.class, true);
indexMap1 = factory.newSortedMap(index1, String.class,
MarshalledObject.class, true);
indexMap2 = factory.newSortedMap(index2, String.class,
MarshalledObject.class, true);
} else {
storeMap1 = factory.newMap(store1, String.class,
MarshalledObject.class, true);
storeMap2 = factory.newMap(store2, String.class,
MarshalledObject.class, true);
indexMap1 = factory.newMap(index1, String.class,
MarshalledObject.class, true);
indexMap2 = factory.newMap(index2, String.class,
MarshalledObject.class, true);
}
}
private void writeAndRead()
throws Exception {
MarshalledObject o1 = new MarshalledObject("data1", "pk1", "ik1", "");
assertNull(storeMap1.put(null, o1));
assertEquals(o1, storeMap1.get("pk1"));
assertEquals(o1, indexMap1.get("ik1"));
MarshalledObject o2 = new MarshalledObject("data2", "pk2", "", "pk1");
assertNull(storeMap2.put(null, o2));
assertEquals(o2, storeMap2.get("pk2"));
assertEquals(o2, indexMap2.get("pk1"));
/*
* store1 contains o1 with primary key "pk1" and index key "ik1"
* store2 contains o2 with primary key "pk2" and foreign key "pk1"
* which is the primary key of store1
*/
storeMap1.remove("pk1");
assertNull(storeMap1.get("pk1"));
assertNull(indexMap1.get("ik1"));
assertNull(storeMap2.get("pk2"));
assertNull(indexMap2.get("pk1"));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,36 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: Enhanced0.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.PrimaryKey;
import com.sleepycat.persist.model.SecondaryKey;
/**
* For running ASMifier -- before any enhancements.
*/
@Entity
class Enhanced0 {
@PrimaryKey
private String f1;
@SecondaryKey(relate=MANY_TO_ONE)
private int f2;
@SecondaryKey(relate=MANY_TO_ONE)
private String f3;
@SecondaryKey(relate=MANY_TO_ONE)
private String f4;
private int f5;
private String f6;
private String f7;
}

View File

@@ -0,0 +1,252 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: Enhanced1.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
import com.sleepycat.persist.impl.Enhanced;
import com.sleepycat.persist.impl.EnhancedAccessor;
import com.sleepycat.persist.impl.EntityInput;
import com.sleepycat.persist.impl.EntityOutput;
import com.sleepycat.persist.impl.Format;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.PrimaryKey;
import com.sleepycat.persist.model.SecondaryKey;
/**
* For running ASMifier -- adds minimal enhancements.
*/
@Entity
class Enhanced1 implements Enhanced {
@PrimaryKey
private String f1;
@SecondaryKey(relate=MANY_TO_ONE)
private int f2;
@SecondaryKey(relate=MANY_TO_ONE)
private String f3;
@SecondaryKey(relate=MANY_TO_ONE)
private String f4;
private int f5;
private String f6;
private String f7;
private int f8;
private int f9;
private int f10;
private int f11;
private int f12;
static {
EnhancedAccessor.registerClass(null, new Enhanced1());
}
public Object bdbNewInstance() {
return new Enhanced1();
}
public Object bdbNewArray(int len) {
return new Enhanced1[len];
}
public boolean bdbIsPriKeyFieldNullOrZero() {
return f1 == null;
}
public void bdbWritePriKeyField(EntityOutput output, Format format) {
output.writeKeyObject(f1, format);
}
public void bdbReadPriKeyField(EntityInput input, Format format) {
f1 = (String) input.readKeyObject(format);
}
public void bdbWriteSecKeyFields(EntityOutput output) {
/* If primary key is an object: */
output.registerPriKeyObject(f1);
/* Always: */
output.writeInt(f2);
output.writeObject(f3, null);
output.writeObject(f4, null);
}
public void bdbReadSecKeyFields(EntityInput input,
int startField,
int endField,
int superLevel) {
/* If primary key is an object: */
input.registerPriKeyObject(f1);
if (superLevel <= 0) {
switch (startField) {
case 0:
f2 = input.readInt();
if (endField == 0) break;
case 1:
f3 = (String) input.readObject();
if (endField == 1) break;
case 2:
f4 = (String) input.readObject();
}
}
}
public void bdbWriteNonKeyFields(EntityOutput output) {
output.writeInt(f5);
output.writeObject(f6, null);
output.writeObject(f7, null);
output.writeInt(f8);
output.writeInt(f9);
output.writeInt(f10);
output.writeInt(f11);
output.writeInt(f12);
}
public void bdbReadNonKeyFields(EntityInput input,
int startField,
int endField,
int superLevel) {
if (superLevel <= 0) {
switch (startField) {
case 0:
f5 = input.readInt();
if (endField == 0) break;
case 1:
f6 = (String) input.readObject();
if (endField == 1) break;
case 2:
f7 = (String) input.readObject();
if (endField == 2) break;
case 3:
f8 = input.readInt();
if (endField == 3) break;
case 4:
f9 = input.readInt();
if (endField == 4) break;
case 5:
f10 = input.readInt();
if (endField == 5) break;
case 6:
f11 = input.readInt();
if (endField == 6) break;
case 7:
f12 = input.readInt();
}
}
}
public boolean bdbNullifyKeyField(Object o,
int field,
int superLevel,
boolean isSecField,
Object keyElement) {
if (superLevel > 0) {
return false;
} else if (isSecField) {
switch (field) {
case 1:
if (f3 != null) {
f3 = null;
return true;
} else {
return false;
}
case 2:
if (f4 != null) {
f4 = null;
return true;
} else {
return false;
}
default:
return false;
}
} else {
switch (field) {
case 1:
if (f6 != null) {
f6 = null;
return true;
} else {
return false;
}
case 2:
if (f7 != null) {
f7 = null;
return true;
} else {
return false;
}
default:
return false;
}
}
}
public Object bdbGetField(Object o,
int field,
int superLevel,
boolean isSecField) {
if (superLevel > 0) {
} else if (isSecField) {
switch (field) {
case 0:
return Integer.valueOf(f2);
case 1:
return f3;
case 2:
return f4;
}
} else {
switch (field) {
case 0:
return Integer.valueOf(f5);
case 1:
return f6;
case 2:
return f7;
}
}
return null;
}
public void bdbSetField(Object o,
int field,
int superLevel,
boolean isSecField,
Object value) {
if (superLevel > 0) {
} else if (isSecField) {
switch (field) {
case 0:
f2 = ((Integer) value).intValue();
return;
case 1:
f3 = (String) value;
return;
case 2:
f4 = (String) value;
return;
}
} else {
switch (field) {
case 0:
f5 = ((Integer) value).intValue();
return;
case 1:
f6 = (String) value;
return;
case 2:
f7 = (String) value;
return;
}
}
}
}

View File

@@ -0,0 +1,110 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: Enhanced2.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import com.sleepycat.persist.impl.EnhancedAccessor;
import com.sleepycat.persist.impl.EntityInput;
import com.sleepycat.persist.impl.EntityOutput;
import com.sleepycat.persist.impl.Format;
import com.sleepycat.persist.model.Persistent;
/**
* For running ASMifier -- entity sublcass.
*/
@Persistent
class Enhanced2 extends Enhanced1 {
static {
EnhancedAccessor.registerClass(null, new Enhanced2());
}
public Object bdbNewInstance() {
return new Enhanced2();
}
public Object bdbNewArray(int len) {
return new Enhanced2[len];
}
public boolean bdbIsPriKeyFieldNullOrZero() {
return super.bdbIsPriKeyFieldNullOrZero();
}
public void bdbWritePriKeyField(EntityOutput output, Format format) {
super.bdbWritePriKeyField(output, format);
}
public void bdbReadPriKeyField(EntityInput input, Format format) {
super.bdbReadPriKeyField(input, format);
}
public void bdbWriteSecKeyFields(EntityOutput output) {
super.bdbWriteSecKeyFields(output);
}
public void bdbReadSecKeyFields(EntityInput input,
int startField,
int endField,
int superLevel) {
if (superLevel != 0) {
super.bdbReadSecKeyFields
(input, startField, endField, superLevel - 1);
}
}
public void bdbWriteNonKeyFields(EntityOutput output) {
super.bdbWriteNonKeyFields(output);
}
public void bdbReadNonKeyFields(EntityInput input,
int startField,
int endField,
int superLevel) {
if (superLevel != 0) {
super.bdbReadNonKeyFields
(input, startField, endField, superLevel - 1);
}
}
public boolean bdbNullifyKeyField(Object o,
int field,
int superLevel,
boolean isSecField,
Object keyElement) {
if (superLevel > 0) {
return super.bdbNullifyKeyField
(o, field, superLevel - 1, isSecField, keyElement);
} else {
return false;
}
}
public Object bdbGetField(Object o,
int field,
int superLevel,
boolean isSecField) {
if (superLevel > 0) {
return super.bdbGetField
(o, field, superLevel - 1, isSecField);
} else {
return null;
}
}
public void bdbSetField(Object o,
int field,
int superLevel,
boolean isSecField,
Object value) {
if (superLevel > 0) {
super.bdbSetField
(o, field, superLevel - 1, isSecField, value);
}
}
}

View File

@@ -0,0 +1,161 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: Enhanced3.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
/*
import java.math.BigIngeter;
import java.math.BigDecimal;
*/
import java.util.Date;
import com.sleepycat.persist.impl.Enhanced;
import com.sleepycat.persist.impl.EnhancedAccessor;
import com.sleepycat.persist.impl.EntityInput;
import com.sleepycat.persist.impl.EntityOutput;
import com.sleepycat.persist.impl.Format;
import com.sleepycat.persist.model.KeyField;
import com.sleepycat.persist.model.Persistent;
/**
* For running ASMifier -- a composite key class using all simple data types,
* does not follow from previous EnhancedN.java files
*/
@Persistent
class Enhanced3 implements Enhanced {
@KeyField(1) boolean z;
@KeyField(2) char c;
@KeyField(3) byte b;
@KeyField(4) short s;
@KeyField(5) int i;
@KeyField(6) long l;
@KeyField(7) float f;
@KeyField(8) double d;
@KeyField(9) Boolean zw;
@KeyField(10) Character cw;
@KeyField(11) Byte bw;
@KeyField(12) Short sw;
@KeyField(13) Integer iw;
@KeyField(14) Long lw;
@KeyField(15) Float fw;
@KeyField(16) Double dw;
@KeyField(17) Date date;
@KeyField(18) String str;
/*
@KeyField(19) BigIngeter bigint;
@KeyField(20) BigDecimal bigdec;
*/
static {
EnhancedAccessor.registerClass(null, new Enhanced3());
}
public Object bdbNewInstance() {
return new Enhanced3();
}
public Object bdbNewArray(int len) {
return new Enhanced3[len];
}
public boolean bdbIsPriKeyFieldNullOrZero() {
return false;
}
public void bdbWritePriKeyField(EntityOutput output, Format format) {
}
public void bdbReadPriKeyField(EntityInput input, Format format) {
}
public void bdbWriteSecKeyFields(EntityOutput output) {
}
public void bdbReadSecKeyFields(EntityInput input,
int startField,
int endField,
int superLevel) {
}
public void bdbWriteNonKeyFields(EntityOutput output) {
output.writeBoolean(z);
output.writeChar(c);
output.writeByte(b);
output.writeShort(s);
output.writeInt(i);
output.writeLong(l);
output.writeSortedFloat(f);
output.writeSortedDouble(d);
output.writeBoolean(zw.booleanValue());
output.writeChar(cw.charValue());
output.writeByte(bw.byteValue());
output.writeShort(sw.shortValue());
output.writeInt(iw.intValue());
output.writeLong(lw.longValue());
output.writeSortedFloat(fw.floatValue());
output.writeSortedDouble(dw.doubleValue());
output.writeLong(date.getTime());
output.writeString(str);
}
public void bdbReadNonKeyFields(EntityInput input,
int startField,
int endField,
int superLevel) {
z = input.readBoolean();
c = input.readChar();
b = input.readByte();
s = input.readShort();
i = input.readInt();
l = input.readLong();
f = input.readSortedFloat();
d = input.readSortedDouble();
zw = Boolean.valueOf(input.readBoolean());
cw = Character.valueOf(input.readChar());
bw = Byte.valueOf(input.readByte());
sw = Short.valueOf(input.readShort());
iw = Integer.valueOf(input.readInt());
lw = Long.valueOf(input.readLong());
fw = Float.valueOf(input.readSortedFloat());
dw = Double.valueOf(input.readSortedDouble());
date = new Date(input.readLong());
str = input.readString();
}
public boolean bdbNullifyKeyField(Object o,
int field,
int superLevel,
boolean isSecField,
Object keyElement) {
// Didn't bother with this one.
return false;
}
public Object bdbGetField(Object o,
int field,
int superLevel,
boolean isSecField) {
// Didn't bother with this one.
return null;
}
public void bdbSetField(Object o,
int field,
int superLevel,
boolean isSecField,
Object value) {
// Didn't bother with this one.
}
}

View File

@@ -0,0 +1,193 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: EvolveCase.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestCase;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.StoreConfig;
import com.sleepycat.persist.evolve.Mutations;
import com.sleepycat.persist.model.ClassMetadata;
import com.sleepycat.persist.model.EntityModel;
import com.sleepycat.persist.model.Persistent;
import com.sleepycat.persist.raw.RawStore;
import com.sleepycat.persist.raw.RawType;
@Persistent
abstract class EvolveCase {
static final String STORE_NAME = "foo";
transient boolean updated;
Mutations getMutations() {
return null;
}
void configure(EntityModel model, StoreConfig config) {
}
String getStoreOpenException() {
return null;
}
int getNRecordsExpected() {
return 1;
}
void checkUnevolvedModel(EntityModel model, Environment env) {
}
void checkEvolvedModel(EntityModel model,
Environment env,
boolean oldTypesExist) {
}
void writeObjects(EntityStore store)
throws DatabaseException {
}
void readObjects(EntityStore store, boolean doUpdate)
throws DatabaseException {
}
void readRawObjects(RawStore store,
boolean expectEvolved,
boolean expectUpdated)
throws DatabaseException {
}
void copyRawObjects(RawStore rawStore, EntityStore newStore)
throws DatabaseException {
}
/**
* Checks for equality and prints the entire values rather than
* abbreviated values like TestCase.assertEquals does.
*/
static void checkEquals(Object expected, Object got) {
if ((expected != null) ? (!expected.equals(got)) : (got != null)) {
TestCase.fail("Expected:\n" + expected + "\nBut got:\n" + got);
}
}
/**
* Asserts than an entity database exists or does not exist.
*/
static void assertDbExists(boolean expectExists,
Environment env,
String entityClassName) {
assertDbExists(expectExists, env, entityClassName, null);
}
/**
* Checks that an entity class exists or does not exist.
*/
static void checkEntity(boolean exists,
EntityModel model,
Environment env,
String className,
int version,
String secKeyName) {
if (exists) {
TestCase.assertNotNull(model.getEntityMetadata(className));
ClassMetadata meta = model.getClassMetadata(className);
TestCase.assertNotNull(meta);
TestCase.assertEquals(version, meta.getVersion());
TestCase.assertTrue(meta.isEntityClass());
RawType raw = model.getRawType(className);
TestCase.assertNotNull(raw);
TestCase.assertEquals(version, raw.getVersion());
} else {
TestCase.assertNull(model.getEntityMetadata(className));
TestCase.assertNull(model.getClassMetadata(className));
TestCase.assertNull(model.getRawType(className));
}
assertDbExists(exists, env, className);
if (secKeyName != null) {
assertDbExists(exists, env, className, secKeyName);
}
}
/**
* Checks that a non-entity class exists or does not exist.
*/
static void checkNonEntity(boolean exists,
EntityModel model,
Environment env,
String className,
int version) {
if (exists) {
ClassMetadata meta = model.getClassMetadata(className);
TestCase.assertNotNull(meta);
TestCase.assertEquals(version, meta.getVersion());
TestCase.assertTrue(!meta.isEntityClass());
RawType raw = model.getRawType(className);
TestCase.assertNotNull(raw);
TestCase.assertEquals(version, raw.getVersion());
} else {
TestCase.assertNull(model.getClassMetadata(className));
TestCase.assertNull(model.getRawType(className));
}
TestCase.assertNull(model.getEntityMetadata(className));
assertDbExists(false, env, className);
}
/**
* Asserts than a database expectExists or does not exist. If keyName is
* null, checks an entity database. If keyName is non-null, checks a
* secondary database.
*/
static void assertDbExists(boolean expectExists,
Environment env,
String entityClassName,
String keyName) {
PersistTestUtils.assertDbExists
(expectExists, env, STORE_NAME, entityClassName, keyName);
}
static void checkVersions(EntityModel model, String name, int version) {
checkVersions(model, new String[] {name}, new int[] {version});
}
static void checkVersions(EntityModel model,
String name1,
int version1,
String name2,
int version2) {
checkVersions
(model, new String[] {name1, name2},
new int[] {version1, version2});
}
private static void checkVersions(EntityModel model,
String[] names,
int[] versions) {
List<RawType> all = model.getAllRawTypeVersions(names[0]);
TestCase.assertNotNull(all);
assert names.length == versions.length;
TestCase.assertEquals(names.length, all.size());
Iterator<RawType> iter = all.iterator();
for (int i = 0; i < names.length; i += 1) {
RawType type = iter.next();
TestCase.assertEquals(versions[i], type.getVersion());
TestCase.assertEquals(names[i], type.getClassName());
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,235 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: EvolveTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import java.io.IOException;
import junit.framework.Test;
import com.sleepycat.persist.evolve.EvolveConfig;
import com.sleepycat.persist.evolve.EvolveEvent;
import com.sleepycat.persist.evolve.EvolveListener;
import com.sleepycat.persist.evolve.EvolveStats;
import com.sleepycat.persist.impl.PersistCatalog;
import com.sleepycat.util.test.SharedTestUtils;
/**
* Runs part two of the EvolveTest. This part is run with the new/updated
* version of EvolveClasses in the classpath. It uses the environment and
* store created by EvolveTestInit. It verifies that it can read/write/evolve
* objects serialized using the old class format, and that it can create new
* objects with the new class format.
*
* @author Mark Hayes
*/
public class EvolveTest extends EvolveTestBase {
public static Test suite()
throws Exception {
return getSuite(EvolveTest.class);
}
private int evolveNRead;
private int evolveNConverted;
boolean useEvolvedClass() {
return true;
}
@Override
public void setUp()
throws IOException {
/* Copy the log files created by EvolveTestInit. */
envHome = getTestInitHome(true /*evolved*/);
envHome.mkdirs();
SharedTestUtils.emptyDir(envHome);
SharedTestUtils.copyFiles(getTestInitHome(false /*evolved*/), envHome);
}
public void testLazyEvolve()
throws Exception {
openEnv();
/*
* Open in raw mode to check unevolved raw object and formats. This
* is possible whether or not we can open the store further below to
* evolve formats without errors.
*/
openRawStore();
caseObj.checkUnevolvedModel(rawStore.getModel(), env);
caseObj.readRawObjects
(rawStore, false /*expectEvolved*/, false /*expectUpdated*/);
closeRawStore();
if (openStoreReadWrite()) {
/*
* When opening read-write, formats are evolved lazily. Check by
* reading evolved objects.
*/
caseObj.checkEvolvedModel
(store.getModel(), env, true /*oldTypesExist*/);
caseObj.readObjects(store, false /*doUpdate*/);
closeStore();
/*
* Read raw objects again to check that the evolved objects are
* returned even though the stored objects were not evolved.
*/
openRawStore();
caseObj.checkEvolvedModel
(rawStore.getModel(), env, true /*oldTypesExist*/);
caseObj.readRawObjects
(rawStore, true /*expectEvolved*/, false /*expectUpdated*/);
closeRawStore();
/*
* Open read-only to ensure that the catalog does not need to
* change (evolve formats) unnecessarily.
*/
PersistCatalog.expectNoClassChanges = true;
try {
openStoreReadOnly();
} finally {
PersistCatalog.expectNoClassChanges = false;
}
caseObj.checkEvolvedModel
(store.getModel(), env, true /*oldTypesExist*/);
caseObj.readObjects(store, false /*doUpdate*/);
closeStore();
/*
* Open read-write to update objects and store them in evolved
* format.
*/
openStoreReadWrite();
caseObj.checkEvolvedModel
(store.getModel(), env, true /*oldTypesExist*/);
caseObj.readObjects(store, true /*doUpdate*/);
caseObj.checkEvolvedModel
(store.getModel(), env, true /*oldTypesExist*/);
closeStore();
/*
* Check raw objects again after the evolved objects were stored.
*/
openRawStore();
caseObj.checkEvolvedModel
(rawStore.getModel(), env, true /*oldTypesExist*/);
caseObj.readRawObjects
(rawStore, true /*expectEvolved*/, true /*expectUpdated*/);
closeRawStore();
}
closeAll();
}
public void testEagerEvolve()
throws Exception {
/* If the store cannot be opened, this test is not appropriate. */
if (caseObj.getStoreOpenException() != null) {
return;
}
EvolveConfig config = new EvolveConfig();
config.setEvolveListener(new EvolveListener() {
public boolean evolveProgress(EvolveEvent event) {
EvolveStats stats = event.getStats();
evolveNRead = stats.getNRead();
evolveNConverted = stats.getNConverted();
return true;
}
});
openEnv();
openStoreReadWrite();
/*
* Evolve and expect that the expected number of entities are
* converted.
*/
int nExpected = caseObj.getNRecordsExpected();
evolveNRead = 0;
evolveNConverted = 0;
PersistCatalog.unevolvedFormatsEncountered = false;
EvolveStats stats = store.evolve(config);
if (nExpected > 0) {
assertTrue(PersistCatalog.unevolvedFormatsEncountered);
}
assertTrue(evolveNRead == nExpected);
assertTrue(evolveNConverted == nExpected);
assertTrue(evolveNConverted >= evolveNRead);
assertEquals(evolveNRead, stats.getNRead());
assertEquals(evolveNConverted, stats.getNConverted());
/* Evolve again and expect that no entities are converted. */
evolveNRead = 0;
evolveNConverted = 0;
PersistCatalog.unevolvedFormatsEncountered = false;
stats = store.evolve(config);
assertTrue(!PersistCatalog.unevolvedFormatsEncountered);
assertTrue(evolveNRead == 0);
assertTrue(evolveNConverted == 0);
assertEquals(0, stats.getNRead());
assertEquals(0, stats.getNConverted());
/* Ensure that we can read all entities without evolution. */
PersistCatalog.unevolvedFormatsEncountered = false;
caseObj.readObjects(store, false /*doUpdate*/);
assertTrue(!PersistCatalog.unevolvedFormatsEncountered);
/*
* When automatic unused type deletion is implemented in the future the
* oldTypesExist parameters below should be changed to false.
*/
/* Open again and try an update. */
caseObj.checkEvolvedModel
(store.getModel(), env, true /*oldTypesExist*/);
caseObj.readObjects(store, true /*doUpdate*/);
caseObj.checkEvolvedModel
(store.getModel(), env, true /*oldTypesExist*/);
closeStore();
/* Open read-only and double check that everything is OK. */
openStoreReadOnly();
caseObj.checkEvolvedModel
(store.getModel(), env, true /*oldTypesExist*/);
caseObj.readObjects(store, false /*doUpdate*/);
caseObj.checkEvolvedModel
(store.getModel(), env, true /*oldTypesExist*/);
closeStore();
/* Check raw objects. */
openRawStore();
caseObj.checkEvolvedModel
(rawStore.getModel(), env, true /*oldTypesExist*/);
caseObj.readRawObjects
(rawStore, true /*expectEvolved*/, true /*expectUpdated*/);
/*
* Test copy raw object to new store via convertRawObject. In this
* test we can pass false for oldTypesExist because newStore starts
* with the new/evolved class model.
*/
openNewStore();
caseObj.copyRawObjects(rawStore, newStore);
caseObj.readObjects(newStore, true /*doUpdate*/);
caseObj.checkEvolvedModel
(newStore.getModel(), env, false /*oldTypesExist*/);
closeNewStore();
closeRawStore();
closeAll();
}
}

View File

@@ -0,0 +1,420 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: EvolveTestBase.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.StoreConfig;
import com.sleepycat.persist.model.AnnotationModel;
import com.sleepycat.persist.model.EntityModel;
import com.sleepycat.persist.raw.RawStore;
import com.sleepycat.util.test.TestEnv;
/**
* Base class for EvolveTest and EvolveTestInit.
*
* @author Mark Hayes
*/
public abstract class EvolveTestBase extends TestCase {
/*
* When adding a evolve test class, three places need to be changed:
* 1) Add the unmodified class to EvolveClass.java.original.
* 2) Add the modified class to EvolveClass.java.
* 3) Add the class name to the ALL list below as a pair of strings. The
* first string in each pair is the name of the original class, and the
* second string is the name of the evolved class or null if the evolved
* name is the same as the original. The index in the list identifies a
* test case, and the class at that position identifies the old and new
* class to use for the test.
*/
private static final String[] ALL = {
"DeletedEntity1_ClassRemoved",
"DeletedEntity1_ClassRemoved_NoMutation",
"DeletedEntity2_ClassRemoved",
"DeletedEntity2_ClassRemoved_WithDeleter",
"DeletedEntity3_AnnotRemoved_NoMutation",
null,
"DeletedEntity4_AnnotRemoved_WithDeleter",
null,
"DeletedEntity5_EntityToPersist_NoMutation",
null,
"DeletedEntity6_EntityToPersist_WithDeleter",
null,
"DeletedPersist1_ClassRemoved_NoMutation",
null,
"DeletedPersist2_ClassRemoved_WithDeleter",
null,
"DeletedPersist3_AnnotRemoved_NoMutation",
null,
"DeletedPersist4_AnnotRemoved_WithDeleter",
null,
"DeletedPersist5_PersistToEntity_NoMutation",
null,
"DeletedPersist6_PersistToEntity_WithDeleter",
null,
"RenamedEntity1_NewEntityName",
"RenamedEntity1_NewEntityName_NoMutation",
"RenamedEntity2_NewEntityName",
"RenamedEntity2_NewEntityName_WithRenamer",
"DeleteSuperclass1_NoMutation",
null,
"DeleteSuperclass2_WithConverter",
null,
"DeleteSuperclass3_WithDeleter",
null,
"DeleteSuperclass4_NoFields",
null,
"DeleteSuperclass5_Top",
null,
"InsertSuperclass1_Between",
null,
"InsertSuperclass2_Top",
null,
"DisallowNonKeyField_PrimitiveToObject",
null,
"DisallowNonKeyField_ObjectToPrimitive",
null,
"DisallowNonKeyField_ObjectToSubtype",
null,
"DisallowNonKeyField_ObjectToUnrelatedSimple",
null,
"DisallowNonKeyField_ObjectToUnrelatedOther",
null,
"DisallowNonKeyField_byte2boolean",
null,
"DisallowNonKeyField_short2byte",
null,
"DisallowNonKeyField_int2short",
null,
"DisallowNonKeyField_long2int",
null,
"DisallowNonKeyField_float2long",
null,
"DisallowNonKeyField_double2float",
null,
"DisallowNonKeyField_Byte2byte",
null,
"DisallowNonKeyField_Character2char",
null,
"DisallowNonKeyField_Short2short",
null,
"DisallowNonKeyField_Integer2int",
null,
"DisallowNonKeyField_Long2long",
null,
"DisallowNonKeyField_Float2float",
null,
"DisallowNonKeyField_Double2double",
null,
"DisallowNonKeyField_float2BigInt",
null,
"DisallowNonKeyField_BigInt2long",
null,
"DisallowSecKeyField_byte2short",
null,
"DisallowSecKeyField_char2int",
null,
"DisallowSecKeyField_short2int",
null,
"DisallowSecKeyField_int2long",
null,
"DisallowSecKeyField_long2float",
null,
"DisallowSecKeyField_float2double",
null,
"DisallowSecKeyField_Byte2short2",
null,
"DisallowSecKeyField_Character2int",
null,
"DisallowSecKeyField_Short2int2",
null,
"DisallowSecKeyField_Integer2long",
null,
"DisallowSecKeyField_Long2float2",
null,
"DisallowSecKeyField_Float2double2",
null,
"DisallowSecKeyField_int2BigInt",
null,
"DisallowPriKeyField_byte2short",
null,
"DisallowPriKeyField_char2int",
null,
"DisallowPriKeyField_short2int",
null,
"DisallowPriKeyField_int2long",
null,
"DisallowPriKeyField_long2float",
null,
"DisallowPriKeyField_float2double",
null,
"DisallowPriKeyField_Byte2short2",
null,
"DisallowPriKeyField_Character2int",
null,
"DisallowPriKeyField_Short2int2",
null,
"DisallowPriKeyField_Integer2long",
null,
"DisallowPriKeyField_Long2float2",
null,
"DisallowPriKeyField_Float2double2",
null,
"DisallowPriKeyField_Long2BigInt",
null,
"DisallowCompositeKeyField_byte2short",
null,
"AllowPriKeyField_Byte2byte2",
null,
"AllowPriKeyField_byte2Byte",
null,
"AllowFieldTypeChanges",
null,
"ConvertExample1_Entity",
null,
"ConvertExample2_Person",
null,
"ConvertExample3_Person",
null,
"ConvertExample4_Entity",
null,
"ConvertExample5_Entity",
null,
"AllowFieldAddDelete",
null,
"ProxiedClass_Entity",
null,
"DisallowChangeProxyFor",
null,
"DisallowDeleteProxyFor",
null,
"ArrayNameChange_Entity",
null,
"AddEnumConstant_Entity",
null,
"DeleteEnumConstant_NoMutation",
null,
"DisallowChangeKeyRelate",
null,
"AllowChangeKeyMetadata",
null,
"AllowAddSecondary",
null,
"FieldAddAndConvert",
null,
};
File envHome;
Environment env;
EntityStore store;
RawStore rawStore;
EntityStore newStore;
String caseClsName;
Class caseCls;
EvolveCase caseObj;
String caseLabel;
static TestSuite getSuite(Class testClass)
throws Exception {
TestSuite suite = new TestSuite();
for (int i = 0; i < ALL.length; i += 2) {
String originalClsName = ALL[i];
String evolvedClsName = ALL[i + 1];
if (evolvedClsName == null) {
evolvedClsName = originalClsName;
}
TestSuite baseSuite = new TestSuite(testClass);
Enumeration e = baseSuite.tests();
while (e.hasMoreElements()) {
EvolveTestBase test = (EvolveTestBase) e.nextElement();
test.init(originalClsName, evolvedClsName);
suite.addTest(test);
}
}
return suite;
}
private void init(String originalClsName,
String evolvedClsName)
throws Exception {
String caseClsName = useEvolvedClass() ?
evolvedClsName : originalClsName;
caseClsName = "com.sleepycat.persist.test.EvolveClasses$" +
caseClsName;
this.caseClsName = caseClsName;
this.caseCls = Class.forName(caseClsName);
this.caseObj = (EvolveCase) caseCls.newInstance();
this.caseLabel = evolvedClsName;
}
abstract boolean useEvolvedClass();
File getTestInitHome(boolean evolved) {
return new File
(System.getProperty("testevolvedir"),
(evolved ? "evolved" : "original") + '/' + caseLabel);
}
@Override
public void tearDown() {
/* Set test name for reporting; cannot be done in the ctor or setUp. */
setName(caseLabel + '-' + getName());
if (env != null) {
try {
closeAll();
} catch (Throwable e) {
System.out.println("During tearDown: " + e);
}
}
envHome = null;
env = null;
store = null;
caseCls = null;
caseObj = null;
caseLabel = null;
/* Do not delete log files so they can be used by 2nd phase of test. */
}
void openEnv()
throws IOException, DatabaseException {
EnvironmentConfig config = TestEnv.TXN.getConfig();
config.setAllowCreate(true);
env = new Environment(envHome, config);
}
/**
* Returns true if the store was opened successfully. Returns false if the
* store could not be opened because an exception was expected -- this is
* not a test failure but no further tests for an EntityStore may be run.
*/
private boolean openStore(StoreConfig config)
throws Exception {
config.setTransactional(true);
config.setMutations(caseObj.getMutations());
EntityModel model = new AnnotationModel();
config.setModel(model);
caseObj.configure(model, config);
String expectException = caseObj.getStoreOpenException();
try {
store = new EntityStore(env, EvolveCase.STORE_NAME, config);
if (expectException != null) {
fail("Expected: " + expectException);
}
} catch (Exception e) {
if (expectException != null) {
//e.printStackTrace();
EvolveCase.checkEquals(expectException, e.toString());
return false;
} else {
throw e;
}
}
return true;
}
boolean openStoreReadOnly()
throws Exception {
StoreConfig config = new StoreConfig();
config.setReadOnly(true);
return openStore(config);
}
boolean openStoreReadWrite()
throws Exception {
StoreConfig config = new StoreConfig();
config.setAllowCreate(true);
return openStore(config);
}
void openRawStore()
throws DatabaseException {
rawStore = new RawStore(env, EvolveCase.STORE_NAME, null);
}
void closeStore()
throws DatabaseException {
if (store != null) {
store.close();
store = null;
}
}
void openNewStore()
throws Exception {
StoreConfig config = new StoreConfig();
config.setAllowCreate(true);
config.setTransactional(true);
EntityModel model = new AnnotationModel();
config.setModel(model);
caseObj.configure(model, config);
newStore = new EntityStore(env, "new", config);
}
void closeNewStore()
throws DatabaseException {
if (newStore != null) {
newStore.close();
newStore = null;
}
}
void closeRawStore()
throws DatabaseException {
if (rawStore != null) {
rawStore.close();
rawStore = null;
}
}
void closeEnv()
throws DatabaseException {
if (env != null) {
env.close();
env = null;
}
}
void closeAll()
throws DatabaseException {
closeStore();
closeRawStore();
closeNewStore();
closeEnv();
}
}

View File

@@ -0,0 +1,56 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: EvolveTestInit.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import java.io.IOException;
import junit.framework.Test;
import com.sleepycat.util.test.SharedTestUtils;
/**
* Runs part one of the EvolveTest. This part is run with the old/original
* version of EvolveClasses in the classpath. It creates a fresh environment
* and store containing instances of the original class. When EvolveTest is
* run, it will read/write/evolve these objects from the store created here.
*
* @author Mark Hayes
*/
public class EvolveTestInit extends EvolveTestBase {
public static Test suite()
throws Exception {
return getSuite(EvolveTestInit.class);
}
boolean useEvolvedClass() {
return false;
}
@Override
public void setUp()
throws IOException {
envHome = getTestInitHome(false /*evolved*/);
envHome.mkdirs();
SharedTestUtils.emptyDir(envHome);
}
public void testInit()
throws Exception {
openEnv();
if (!openStoreReadWrite()) {
fail();
}
caseObj.writeObjects(store);
caseObj.checkUnevolvedModel(store.getModel(), env);
closeAll();
}
}

View File

@@ -0,0 +1,324 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: ForeignKeyTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import static com.sleepycat.persist.model.DeleteAction.ABORT;
import static com.sleepycat.persist.model.DeleteAction.CASCADE;
import static com.sleepycat.persist.model.DeleteAction.NULLIFY;
import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE;
import java.util.Enumeration;
import junit.framework.Test;
import junit.framework.TestSuite;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Transaction;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.PrimaryIndex;
import com.sleepycat.persist.SecondaryIndex;
import com.sleepycat.persist.StoreConfig;
import com.sleepycat.persist.model.DeleteAction;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.Persistent;
import com.sleepycat.persist.model.PrimaryKey;
import com.sleepycat.persist.model.SecondaryKey;
import com.sleepycat.util.test.TxnTestCase;
/**
* @author Mark Hayes
*/
public class ForeignKeyTest extends TxnTestCase {
private static final DeleteAction[] ACTIONS = {
ABORT,
NULLIFY,
CASCADE,
};
private static final String[] ACTION_LABELS = {
"ABORT",
"NULLIFY",
"CASCADE",
};
public static Test suite() {
TestSuite suite = new TestSuite();
for (int i = 0; i < ACTIONS.length; i += 1) {
for (int j = 0; j < 2; j++) {
TestSuite txnSuite = txnTestSuite
(ForeignKeyTest.class, null, null);
Enumeration e = txnSuite.tests();
while (e.hasMoreElements()) {
ForeignKeyTest test = (ForeignKeyTest) e.nextElement();
test.onDelete = ACTIONS[i];
test.onDeleteLabel = ACTION_LABELS[i];
test.useSubclass = (j == 0);
test.useSubclassLabel =
(j == 0) ? "UseSubclass" : "UseBaseclass";
suite.addTest(test);
}
}
}
return suite;
}
private EntityStore store;
private PrimaryIndex<String,Entity1> pri1;
private PrimaryIndex<String,Entity2> pri2;
private SecondaryIndex<String,String,Entity1> sec1;
private SecondaryIndex<String,String,Entity2> sec2;
private DeleteAction onDelete;
private String onDeleteLabel;
private boolean useSubclass;
private String useSubclassLabel;
public void tearDown()
throws Exception {
super.tearDown();
setName(getName() + '-' + onDeleteLabel + "-" + useSubclassLabel);
}
private void open()
throws DatabaseException {
StoreConfig config = new StoreConfig();
config.setAllowCreate(envConfig.getAllowCreate());
config.setTransactional(envConfig.getTransactional());
store = new EntityStore(env, "test", config);
pri1 = store.getPrimaryIndex(String.class, Entity1.class);
sec1 = store.getSecondaryIndex(pri1, String.class, "sk");
pri2 = store.getPrimaryIndex(String.class, Entity2.class);
sec2 = store.getSecondaryIndex
(pri2, String.class, "sk_" + onDeleteLabel);
}
private void close()
throws DatabaseException {
store.close();
}
public void testForeignKeys()
throws Exception {
open();
Transaction txn = txnBegin();
Entity1 o1 = new Entity1("pk1", "sk1");
assertNull(pri1.put(txn, o1));
assertEquals(o1, pri1.get(txn, "pk1", null));
assertEquals(o1, sec1.get(txn, "sk1", null));
Entity2 o2 = (useSubclass ?
new Entity3("pk2", "pk1", onDelete) :
new Entity2("pk2", "pk1", onDelete));
assertNull(pri2.put(txn, o2));
assertEquals(o2, pri2.get(txn, "pk2", null));
assertEquals(o2, sec2.get(txn, "pk1", null));
txnCommit(txn);
txn = txnBegin();
/*
* pri1 contains o1 with primary key "pk1" and index key "sk1".
*
* pri2 contains o2 with primary key "pk2" and foreign key "pk1",
* which is the primary key of pri1.
*/
if (onDelete == ABORT) {
/* Test that we abort trying to delete a referenced key. */
try {
pri1.delete(txn, "pk1");
fail();
} catch (DatabaseException expected) {
txnAbort(txn);
txn = txnBegin();
}
/*
* Test that we can put a record into store2 with a null foreign
* key value.
*/
o2 = (useSubclass ?
new Entity3("pk2", null, onDelete) :
new Entity2("pk2", null, onDelete));
assertNotNull(pri2.put(txn, o2));
assertEquals(o2, pri2.get(txn, "pk2", null));
/*
* The index2 record should have been deleted since the key was set
* to null above.
*/
assertNull(sec2.get(txn, "pk1", null));
/*
* Test that now we can delete the record in store1, since it is no
* longer referenced.
*/
assertNotNull(pri1.delete(txn, "pk1"));
assertNull(pri1.get(txn, "pk1", null));
assertNull(sec1.get(txn, "sk1", null));
} else if (onDelete == NULLIFY) {
/* Delete the referenced key. */
assertNotNull(pri1.delete(txn, "pk1"));
assertNull(pri1.get(txn, "pk1", null));
assertNull(sec1.get(txn, "sk1", null));
/*
* The store2 record should still exist, but should have an empty
* secondary key since it was nullified.
*/
o2 = pri2.get(txn, "pk2", null);
assertNotNull(o2);
assertEquals("pk2", o2.pk);
assertEquals(null, o2.getSk(onDelete));
} else if (onDelete == CASCADE) {
/* Delete the referenced key. */
assertNotNull(pri1.delete(txn, "pk1"));
assertNull(pri1.get(txn, "pk1", null));
assertNull(sec1.get(txn, "sk1", null));
/* The store2 record should have deleted also. */
assertNull(pri2.get(txn, "pk2", null));
assertNull(sec2.get(txn, "pk1", null));
} else {
throw new IllegalStateException();
}
/*
* Test that a foreign key value may not be used that is not present in
* the foreign store. "pk2" is not in store1 in this case.
*/
Entity2 o3 = (useSubclass ?
new Entity3("pk3", "pk2", onDelete) :
new Entity2("pk3", "pk2", onDelete));
try {
pri2.put(txn, o3);
fail();
} catch (DatabaseException expected) {
}
txnCommit(txn);
close();
}
@Entity
static class Entity1 {
@PrimaryKey
String pk;
@SecondaryKey(relate=ONE_TO_ONE)
String sk;
private Entity1() {}
Entity1(String pk, String sk) {
this.pk = pk;
this.sk = sk;
}
@Override
public boolean equals(Object other) {
Entity1 o = (Entity1) other;
return nullOrEqual(pk, o.pk) &&
nullOrEqual(sk, o.sk);
}
}
@Entity
static class Entity2 {
@PrimaryKey
String pk;
@SecondaryKey(relate=ONE_TO_ONE, relatedEntity=Entity1.class,
onRelatedEntityDelete=ABORT)
String sk_ABORT;
@SecondaryKey(relate=ONE_TO_ONE, relatedEntity=Entity1.class,
onRelatedEntityDelete=CASCADE)
String sk_CASCADE;
@SecondaryKey(relate=ONE_TO_ONE, relatedEntity=Entity1.class,
onRelatedEntityDelete=NULLIFY)
String sk_NULLIFY;
private Entity2() {}
Entity2(String pk, String sk, DeleteAction action) {
this.pk = pk;
switch (action) {
case ABORT:
sk_ABORT = sk;
break;
case CASCADE:
sk_CASCADE = sk;
break;
case NULLIFY:
sk_NULLIFY = sk;
break;
default:
throw new IllegalArgumentException();
}
}
String getSk(DeleteAction action) {
switch (action) {
case ABORT:
return sk_ABORT;
case CASCADE:
return sk_CASCADE;
case NULLIFY:
return sk_NULLIFY;
default:
throw new IllegalArgumentException();
}
}
@Override
public boolean equals(Object other) {
Entity2 o = (Entity2) other;
return nullOrEqual(pk, o.pk) &&
nullOrEqual(sk_ABORT, o.sk_ABORT) &&
nullOrEqual(sk_CASCADE, o.sk_CASCADE) &&
nullOrEqual(sk_NULLIFY, o.sk_NULLIFY);
}
}
@Persistent
static class Entity3 extends Entity2 {
Entity3() {}
Entity3(String pk, String sk, DeleteAction action) {
super(pk, sk, action);
}
}
static boolean nullOrEqual(Object o1, Object o2) {
if (o1 == null) {
return o2 == null;
} else {
return o1.equals(o2);
}
}
}

View File

@@ -0,0 +1,864 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: IndexTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import static com.sleepycat.persist.model.Relationship.MANY_TO_MANY;
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
import static com.sleepycat.persist.model.Relationship.ONE_TO_MANY;
import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import junit.framework.Test;
import com.sleepycat.collections.MapEntryParameter;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Transaction;
import com.sleepycat.persist.EntityCursor;
import com.sleepycat.persist.EntityIndex;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.PrimaryIndex;
import com.sleepycat.persist.SecondaryIndex;
import com.sleepycat.persist.StoreConfig;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.PrimaryKey;
import com.sleepycat.persist.model.SecondaryKey;
import com.sleepycat.persist.raw.RawObject;
import com.sleepycat.persist.raw.RawStore;
import com.sleepycat.persist.raw.RawType;
import com.sleepycat.util.test.TxnTestCase;
/**
* Tests EntityIndex and EntityCursor in all their permutations.
*
* @author Mark Hayes
*/
public class IndexTest extends TxnTestCase {
private static final int N_RECORDS = 5;
private static final int THREE_TO_ONE = 3;
public static Test suite() {
return txnTestSuite(IndexTest.class, null,
null);
//new String[] { TxnTestCase.TXN_NULL});
}
private EntityStore store;
private PrimaryIndex<Integer,MyEntity> primary;
private SecondaryIndex<Integer,Integer,MyEntity> oneToOne;
private SecondaryIndex<Integer,Integer,MyEntity> manyToOne;
private SecondaryIndex<Integer,Integer,MyEntity> oneToMany;
private SecondaryIndex<Integer,Integer,MyEntity> manyToMany;
private RawStore rawStore;
private RawType entityType;
private PrimaryIndex<Object,RawObject> primaryRaw;
private SecondaryIndex<Object,Object,RawObject> oneToOneRaw;
private SecondaryIndex<Object,Object,RawObject> manyToOneRaw;
private SecondaryIndex<Object,Object,RawObject> oneToManyRaw;
private SecondaryIndex<Object,Object,RawObject> manyToManyRaw;
/**
* Opens the store.
*/
private void open()
throws DatabaseException {
StoreConfig config = new StoreConfig();
config.setAllowCreate(envConfig.getAllowCreate());
config.setTransactional(envConfig.getTransactional());
store = new EntityStore(env, "test", config);
primary = store.getPrimaryIndex(Integer.class, MyEntity.class);
oneToOne =
store.getSecondaryIndex(primary, Integer.class, "oneToOne");
manyToOne =
store.getSecondaryIndex(primary, Integer.class, "manyToOne");
oneToMany =
store.getSecondaryIndex(primary, Integer.class, "oneToMany");
manyToMany =
store.getSecondaryIndex(primary, Integer.class, "manyToMany");
assertNotNull(primary);
assertNotNull(oneToOne);
assertNotNull(manyToOne);
assertNotNull(oneToMany);
assertNotNull(manyToMany);
rawStore = new RawStore(env, "test", config);
String clsName = MyEntity.class.getName();
entityType = rawStore.getModel().getRawType(clsName);
assertNotNull(entityType);
primaryRaw = rawStore.getPrimaryIndex(clsName);
oneToOneRaw = rawStore.getSecondaryIndex(clsName, "oneToOne");
manyToOneRaw = rawStore.getSecondaryIndex(clsName, "manyToOne");
oneToManyRaw = rawStore.getSecondaryIndex(clsName, "oneToMany");
manyToManyRaw = rawStore.getSecondaryIndex(clsName, "manyToMany");
assertNotNull(primaryRaw);
assertNotNull(oneToOneRaw);
assertNotNull(manyToOneRaw);
assertNotNull(oneToManyRaw);
assertNotNull(manyToManyRaw);
}
/**
* Closes the store.
*/
private void close()
throws DatabaseException {
store.close();
store = null;
rawStore.close();
rawStore = null;
}
/**
* The store must be closed before closing the environment.
*/
public void tearDown()
throws Exception {
try {
if (rawStore != null) {
rawStore.close();
}
} catch (Throwable e) {
System.out.println("During tearDown: " + e);
}
try {
if (store != null) {
store.close();
}
} catch (Throwable e) {
System.out.println("During tearDown: " + e);
}
store = null;
rawStore = null;
super.tearDown();
}
/**
* Primary keys: {0, 1, 2, 3, 4}
*/
public void testPrimary()
throws DatabaseException {
SortedMap<Integer,SortedSet<Integer>> expected =
new TreeMap<Integer,SortedSet<Integer>>();
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
SortedSet<Integer> values = new TreeSet<Integer>();
values.add(priKey);
expected.put(priKey, values);
}
open();
addEntities(primary);
checkIndex(primary, expected, keyGetter, entityGetter);
checkIndex(primaryRaw, expected, rawKeyGetter, rawEntityGetter);
/* Close and reopen, then recheck indices. */
close();
open();
checkIndex(primary, expected, keyGetter, entityGetter);
checkIndex(primaryRaw, expected, rawKeyGetter, rawEntityGetter);
/* Check primary delete, last key first for variety. */
for (int priKey = N_RECORDS - 1; priKey >= 0; priKey -= 1) {
boolean useRaw = ((priKey & 1) != 0);
Transaction txn = txnBegin();
if (useRaw) {
primaryRaw.delete(txn, priKey);
} else {
primary.delete(txn, priKey);
}
txnCommit(txn);
expected.remove(priKey);
checkIndex(primary, expected, keyGetter, entityGetter);
}
checkAllEmpty();
/* Check PrimaryIndex put operations. */
MyEntity e;
Transaction txn = txnBegin();
/* put() */
e = primary.put(txn, new MyEntity(1));
assertNull(e);
e = primary.get(txn, 1, null);
assertEquals(1, e.key);
/* putNoReturn() */
primary.putNoReturn(txn, new MyEntity(2));
e = primary.get(txn, 2, null);
assertEquals(2, e.key);
/* putNoOverwrite */
assertTrue(!primary.putNoOverwrite(txn, new MyEntity(1)));
assertTrue(!primary.putNoOverwrite(txn, new MyEntity(2)));
assertTrue(primary.putNoOverwrite(txn, new MyEntity(3)));
e = primary.get(txn, 3, null);
assertEquals(3, e.key);
txnCommit(txn);
close();
}
/**
* { 0:0, 1:-1, 2:-2, 3:-3, 4:-4 }
*/
public void testOneToOne()
throws DatabaseException {
SortedMap<Integer,SortedSet<Integer>> expected =
new TreeMap<Integer,SortedSet<Integer>>();
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
SortedSet<Integer> values = new TreeSet<Integer>();
values.add(priKey);
Integer secKey = (-priKey);
expected.put(secKey, values);
}
open();
addEntities(primary);
checkSecondary(oneToOne, oneToOneRaw, expected);
checkDelete(oneToOne, oneToOneRaw, expected);
close();
}
/**
* { 0:0, 1:1, 2:2, 3:0, 4:1 }
*/
public void testManyToOne()
throws DatabaseException {
SortedMap<Integer,SortedSet<Integer>> expected =
new TreeMap<Integer,SortedSet<Integer>>();
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
Integer secKey = priKey % THREE_TO_ONE;
SortedSet<Integer> values = expected.get(secKey);
if (values == null) {
values = new TreeSet<Integer>();
expected.put(secKey, values);
}
values.add(priKey);
}
open();
addEntities(primary);
checkSecondary(manyToOne, manyToOneRaw, expected);
checkDelete(manyToOne, manyToOneRaw, expected);
close();
}
/**
* { 0:{}, 1:{10}, 2:{20,21}, 3:{30,31,32}, 4:{40,41,42,43}
*/
public void testOneToMany()
throws DatabaseException {
SortedMap<Integer,SortedSet<Integer>> expected =
new TreeMap<Integer,SortedSet<Integer>>();
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
for (int i = 0; i < priKey; i += 1) {
Integer secKey = (N_RECORDS * priKey) + i;
SortedSet<Integer> values = expected.get(secKey);
if (values == null) {
values = new TreeSet<Integer>();
expected.put(secKey, values);
}
values.add(priKey);
}
}
open();
addEntities(primary);
checkSecondary(oneToMany, oneToManyRaw, expected);
checkDelete(oneToMany, oneToManyRaw, expected);
close();
}
/**
* { 0:{}, 1:{0}, 2:{0,1}, 3:{0,1,2}, 4:{0,1,2,3}
*/
public void testManyToMany()
throws DatabaseException {
SortedMap<Integer,SortedSet<Integer>> expected =
new TreeMap<Integer,SortedSet<Integer>>();
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
for (int i = 0; i < priKey; i += 1) {
Integer secKey = i;
SortedSet<Integer> values = expected.get(secKey);
if (values == null) {
values = new TreeSet<Integer>();
expected.put(secKey, values);
}
values.add(priKey);
}
}
open();
addEntities(primary);
checkSecondary(manyToMany, manyToManyRaw, expected);
checkDelete(manyToMany, manyToManyRaw, expected);
close();
}
private void addEntities(PrimaryIndex<Integer,MyEntity> primary)
throws DatabaseException {
Transaction txn = txnBegin();
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
MyEntity prev = primary.put(txn, new MyEntity(priKey));
assertNull(prev);
}
txnCommit(txn);
}
private void checkDelete(SecondaryIndex<Integer,Integer,MyEntity> index,
SecondaryIndex<Object,Object,RawObject> indexRaw,
SortedMap<Integer,SortedSet<Integer>> expected)
throws DatabaseException {
SortedMap<Integer,SortedSet<Integer>> expectedSubIndex =
new TreeMap<Integer,SortedSet<Integer>>();
while (expected.size() > 0) {
Integer delSecKey = expected.firstKey();
SortedSet<Integer> deletedPriKeys = expected.remove(delSecKey);
for (SortedSet<Integer> priKeys : expected.values()) {
priKeys.removeAll(deletedPriKeys);
}
Transaction txn = txnBegin();
boolean deleted = index.delete(txn, delSecKey);
assertEquals(deleted, !deletedPriKeys.isEmpty());
deleted = index.delete(txn, delSecKey);
assertTrue(!deleted);
assertNull(index.get(txn, delSecKey, null));
txnCommit(txn);
checkSecondary(index, indexRaw, expected);
}
/*
* Delete remaining records so that the primary index is empty. Use
* the RawStore for variety.
*/
Transaction txn = txnBegin();
for (int priKey = 0; priKey < N_RECORDS; priKey += 1) {
primaryRaw.delete(txn, priKey);
}
txnCommit(txn);
checkAllEmpty();
}
private void checkSecondary(SecondaryIndex<Integer,Integer,MyEntity> index,
SecondaryIndex<Object,Object,RawObject>
indexRaw,
SortedMap<Integer,SortedSet<Integer>> expected)
throws DatabaseException {
checkIndex(index, expected, keyGetter, entityGetter);
checkIndex(index.keysIndex(), expected, keyGetter, keyGetter);
checkIndex(indexRaw, expected, rawKeyGetter, rawEntityGetter);
checkIndex(indexRaw.keysIndex(), expected, rawKeyGetter, rawKeyGetter);
SortedMap<Integer,SortedSet<Integer>> expectedSubIndex =
new TreeMap<Integer,SortedSet<Integer>>();
for (Integer secKey : expected.keySet()) {
expectedSubIndex.clear();
for (Integer priKey : expected.get(secKey)) {
SortedSet<Integer> values = new TreeSet<Integer>();
values.add(priKey);
expectedSubIndex.put(priKey, values);
}
checkIndex(index.subIndex(secKey),
expectedSubIndex,
keyGetter,
entityGetter);
checkIndex(indexRaw.subIndex(secKey),
expectedSubIndex,
rawKeyGetter,
rawEntityGetter);
}
}
private <K,V> void checkIndex(EntityIndex<K,V> index,
SortedMap<Integer,SortedSet<Integer>>
expected,
Getter<K> kGetter,
Getter<V> vGetter)
throws DatabaseException {
SortedMap<K,V> map = index.sortedMap();
Transaction txn = txnBegin();
for (int i : expected.keySet()) {
K k = kGetter.fromInt(i);
SortedSet<Integer> dups = expected.get(i);
if (dups.isEmpty()) {
/* EntityIndex */
V v = index.get(txn, k, null);
assertNull(v);
assertTrue(!index.contains(txn, k, null));
/* Map/Collection */
v = map.get(i);
assertNull(v);
assertTrue(!map.containsKey(i));
} else {
int j = dups.first();
/* EntityIndex */
V v = index.get(txn, k, null);
assertNotNull(v);
assertEquals(j, vGetter.getKey(v));
assertTrue(index.contains(txn, k, null));
/* Map/Collection */
v = map.get(i);
assertNotNull(v);
assertEquals(j, vGetter.getKey(v));
assertTrue(map.containsKey(i));
assertTrue("" + i + ' ' + j + ' ' + v + ' ' + map,
map.containsValue(v));
assertTrue(map.keySet().contains(i));
assertTrue(map.values().contains(v));
assertTrue
(map.entrySet().contains(new MapEntryParameter(i, v)));
}
}
txnCommit(txn);
int keysSize = expandKeySize(expected);
int valuesSize = expandValueSize(expected);
/* EntityIndex.count */
assertEquals("keysSize=" + keysSize, (long) valuesSize, index.count());
/* Map/Collection size */
assertEquals(valuesSize, map.size());
assertEquals(valuesSize, map.values().size());
assertEquals(valuesSize, map.entrySet().size());
assertEquals(keysSize, map.keySet().size());
/* Map/Collection isEmpty */
assertEquals(valuesSize == 0, map.isEmpty());
assertEquals(valuesSize == 0, map.values().isEmpty());
assertEquals(valuesSize == 0, map.entrySet().isEmpty());
assertEquals(keysSize == 0, map.keySet().isEmpty());
txn = txnBeginCursor();
/* Unconstrained cursors. */
checkCursor
(index.keys(txn, null),
map.keySet(), true,
expandKeys(expected), kGetter);
checkCursor
(index.entities(txn, null),
map.values(), false,
expandValues(expected), vGetter);
/* Range cursors. */
if (expected.isEmpty()) {
checkOpenRanges(txn, 0, index, expected, kGetter, vGetter);
checkClosedRanges(txn, 0, 1, index, expected, kGetter, vGetter);
} else {
int firstKey = expected.firstKey();
int lastKey = expected.lastKey();
for (int i = firstKey - 1; i <= lastKey + 1; i += 1) {
checkOpenRanges(txn, i, index, expected, kGetter, vGetter);
int j = i + 1;
if (j < lastKey + 1) {
checkClosedRanges
(txn, i, j, index, expected, kGetter, vGetter);
}
}
}
txnCommit(txn);
}
private <K,V> void checkOpenRanges(Transaction txn, int i,
EntityIndex<K,V> index,
SortedMap<Integer,SortedSet<Integer>>
expected,
Getter<K> kGetter,
Getter<V> vGetter)
throws DatabaseException {
SortedMap<K,V> map = index.sortedMap();
SortedMap<Integer,SortedSet<Integer>> rangeExpected;
K k = kGetter.fromInt(i);
K kPlusOne = kGetter.fromInt(i + 1);
/* Head range exclusive. */
rangeExpected = expected.headMap(i);
checkCursor
(index.keys(txn, null, false, k, false, null),
map.headMap(k).keySet(), true,
expandKeys(rangeExpected), kGetter);
checkCursor
(index.entities(txn, null, false, k, false, null),
map.headMap(k).values(), false,
expandValues(rangeExpected), vGetter);
/* Head range inclusive. */
rangeExpected = expected.headMap(i + 1);
checkCursor
(index.keys(txn, null, false, k, true, null),
map.headMap(kPlusOne).keySet(), true,
expandKeys(rangeExpected), kGetter);
checkCursor
(index.entities(txn, null, false, k, true, null),
map.headMap(kPlusOne).values(), false,
expandValues(rangeExpected), vGetter);
/* Tail range exclusive. */
rangeExpected = expected.tailMap(i + 1);
checkCursor
(index.keys(txn, k, false, null, false, null),
map.tailMap(kPlusOne).keySet(), true,
expandKeys(rangeExpected), kGetter);
checkCursor
(index.entities(txn, k, false, null, false, null),
map.tailMap(kPlusOne).values(), false,
expandValues(rangeExpected), vGetter);
/* Tail range inclusive. */
rangeExpected = expected.tailMap(i);
checkCursor
(index.keys(txn, k, true, null, false, null),
map.tailMap(k).keySet(), true,
expandKeys(rangeExpected), kGetter);
checkCursor
(index.entities(txn, k, true, null, false, null),
map.tailMap(k).values(), false,
expandValues(rangeExpected), vGetter);
}
private <K,V> void checkClosedRanges(Transaction txn, int i, int j,
EntityIndex<K,V> index,
SortedMap<Integer,SortedSet<Integer>>
expected,
Getter<K> kGetter,
Getter<V> vGetter)
throws DatabaseException {
SortedMap<K,V> map = index.sortedMap();
SortedMap<Integer,SortedSet<Integer>> rangeExpected;
K k = kGetter.fromInt(i);
K kPlusOne = kGetter.fromInt(i + 1);
K l = kGetter.fromInt(j);
K lPlusOne = kGetter.fromInt(j + 1);
/* Sub range exclusive. */
rangeExpected = expected.subMap(i + 1, j);
checkCursor
(index.keys(txn, k, false, l, false, null),
map.subMap(kPlusOne, l).keySet(), true,
expandKeys(rangeExpected), kGetter);
checkCursor
(index.entities(txn, k, false, l, false, null),
map.subMap(kPlusOne, l).values(), false,
expandValues(rangeExpected), vGetter);
/* Sub range inclusive. */
rangeExpected = expected.subMap(i, j + 1);
checkCursor
(index.keys(txn, k, true, l, true, null),
map.subMap(k, lPlusOne).keySet(), true,
expandKeys(rangeExpected), kGetter);
checkCursor
(index.entities(txn, k, true, l, true, null),
map.subMap(k, lPlusOne).values(), false,
expandValues(rangeExpected), vGetter);
}
private List<List<Integer>>
expandKeys(SortedMap<Integer,SortedSet<Integer>> map) {
List<List<Integer>> list = new ArrayList<List<Integer>>();
for (Integer key : map.keySet()) {
SortedSet<Integer> values = map.get(key);
List<Integer> dups = new ArrayList<Integer>();
for (int i = 0; i < values.size(); i += 1) {
dups.add(key);
}
list.add(dups);
}
return list;
}
private List<List<Integer>>
expandValues(SortedMap<Integer,SortedSet<Integer>> map) {
List<List<Integer>> list = new ArrayList<List<Integer>>();
for (SortedSet<Integer> values : map.values()) {
list.add(new ArrayList<Integer>(values));
}
return list;
}
private int expandKeySize(SortedMap<Integer,SortedSet<Integer>> map) {
int size = 0;
for (SortedSet<Integer> values : map.values()) {
if (values.size() > 0) {
size += 1;
}
}
return size;
}
private int expandValueSize(SortedMap<Integer,SortedSet<Integer>> map) {
int size = 0;
for (SortedSet<Integer> values : map.values()) {
size += values.size();
}
return size;
}
private <T> void checkCursor(EntityCursor<T> cursor,
Collection<T> collection,
boolean collectionIsKeySet,
List<List<Integer>> expected,
Getter<T> getter)
throws DatabaseException {
boolean first;
boolean firstDup;
Iterator<T> iterator = collection.iterator();
for (List<Integer> dups : expected) {
for (int i : dups) {
T o = cursor.next();
assertNotNull(o);
assertEquals(i, getter.getKey(o));
/* Value iterator over duplicates. */
if (!collectionIsKeySet) {
assertTrue(iterator.hasNext());
o = iterator.next();
assertNotNull(o);
assertEquals(i, getter.getKey(o));
}
}
}
first = true;
for (List<Integer> dups : expected) {
firstDup = true;
for (int i : dups) {
T o = first ? cursor.first()
: (firstDup ? cursor.next() : cursor.nextDup());
assertNotNull(o);
assertEquals(i, getter.getKey(o));
first = false;
firstDup = false;
}
}
first = true;
for (List<Integer> dups : expected) {
if (!dups.isEmpty()) {
int i = dups.get(0);
T o = first ? cursor.first() : cursor.nextNoDup();
assertNotNull(o);
assertEquals(i, getter.getKey(o));
/* Key iterator over non-duplicates. */
if (collectionIsKeySet) {
assertTrue(iterator.hasNext());
o = iterator.next();
assertNotNull(o);
assertEquals(i, getter.getKey(o));
}
first = false;
}
}
List<List<Integer>> reversed = new ArrayList<List<Integer>>();
for (List<Integer> dups : expected) {
ArrayList<Integer> reversedDups = new ArrayList<Integer>(dups);
Collections.reverse(reversedDups);
reversed.add(reversedDups);
}
Collections.reverse(reversed);
first = true;
for (List<Integer> dups : reversed) {
for (int i : dups) {
T o = first ? cursor.last() : cursor.prev();
assertNotNull(o);
assertEquals(i, getter.getKey(o));
first = false;
}
}
first = true;
for (List<Integer> dups : reversed) {
firstDup = true;
for (int i : dups) {
T o = first ? cursor.last()
: (firstDup ? cursor.prev() : cursor.prevDup());
assertNotNull(o);
assertEquals(i, getter.getKey(o));
first = false;
firstDup = false;
}
}
first = true;
for (List<Integer> dups : reversed) {
if (!dups.isEmpty()) {
int i = dups.get(0);
T o = first ? cursor.last() : cursor.prevNoDup();
assertNotNull(o);
assertEquals(i, getter.getKey(o));
first = false;
}
}
cursor.close();
}
private void checkAllEmpty()
throws DatabaseException {
checkEmpty(primary);
checkEmpty(oneToOne);
checkEmpty(oneToMany);
checkEmpty(manyToOne);
checkEmpty(manyToMany);
}
private <K,V> void checkEmpty(EntityIndex<K,V> index)
throws DatabaseException {
EntityCursor<K> keys = index.keys();
assertNull(keys.next());
assertTrue(!keys.iterator().hasNext());
keys.close();
EntityCursor<V> entities = index.entities();
assertNull(entities.next());
assertTrue(!entities.iterator().hasNext());
entities.close();
}
private interface Getter<T> {
int getKey(T o);
T fromInt(int i);
}
private static Getter<MyEntity> entityGetter =
new Getter<MyEntity>() {
public int getKey(MyEntity o) {
return o.key;
}
public MyEntity fromInt(int i) {
throw new UnsupportedOperationException();
}
};
private static Getter<Integer> keyGetter =
new Getter<Integer>() {
public int getKey(Integer o) {
return o;
}
public Integer fromInt(int i) {
return Integer.valueOf(i);
}
};
private static Getter<RawObject> rawEntityGetter =
new Getter<RawObject>() {
public int getKey(RawObject o) {
Object val = o.getValues().get("key");
return ((Integer) val).intValue();
}
public RawObject fromInt(int i) {
throw new UnsupportedOperationException();
}
};
private static Getter<Object> rawKeyGetter =
new Getter<Object>() {
public int getKey(Object o) {
return ((Integer) o).intValue();
}
public Object fromInt(int i) {
return Integer.valueOf(i);
}
};
@Entity
private static class MyEntity {
@PrimaryKey
private int key;
@SecondaryKey(relate=ONE_TO_ONE)
private int oneToOne;
@SecondaryKey(relate=MANY_TO_ONE)
private int manyToOne;
@SecondaryKey(relate=ONE_TO_MANY)
private Set<Integer> oneToMany = new TreeSet<Integer>();
@SecondaryKey(relate=MANY_TO_MANY)
private Set<Integer> manyToMany = new TreeSet<Integer>();
private MyEntity() {}
private MyEntity(int key) {
/* example keys: {0, 1, 2, 3, 4} */
this.key = key;
/* { 0:0, 1:-1, 2:-2, 3:-3, 4:-4 } */
oneToOne = -key;
/* { 0:0, 1:1, 2:2, 3:0, 4:1 } */
manyToOne = key % THREE_TO_ONE;
/* { 0:{}, 1:{10}, 2:{20,21}, 3:{30,31,32}, 4:{40,41,42,43} */
for (int i = 0; i < key; i += 1) {
oneToMany.add((N_RECORDS * key) + i);
}
/* { 0:{}, 1:{0}, 2:{0,1}, 3:{0,1,2}, 4:{0,1,2,3} */
for (int i = 0; i < key; i += 1) {
manyToMany.add(i);
}
}
@Override
public String toString() {
return "MyEntity " + key;
}
}
}

View File

@@ -0,0 +1,174 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: JoinTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
import java.util.ArrayList;
import java.util.List;
import junit.framework.Test;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Transaction;
import com.sleepycat.persist.EntityJoin;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.ForwardCursor;
import com.sleepycat.persist.PrimaryIndex;
import com.sleepycat.persist.SecondaryIndex;
import com.sleepycat.persist.StoreConfig;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.PrimaryKey;
import com.sleepycat.persist.model.SecondaryKey;
import com.sleepycat.util.test.TxnTestCase;
/**
* @author Mark Hayes
*/
public class JoinTest extends TxnTestCase {
private static final int N_RECORDS = 5;
public static Test suite() {
return txnTestSuite(JoinTest.class, null, null);
}
private EntityStore store;
private PrimaryIndex<Integer,MyEntity> primary;
private SecondaryIndex<Integer,Integer,MyEntity> sec1;
private SecondaryIndex<Integer,Integer,MyEntity> sec2;
private SecondaryIndex<Integer,Integer,MyEntity> sec3;
/**
* Opens the store.
*/
private void open()
throws DatabaseException {
StoreConfig config = new StoreConfig();
config.setAllowCreate(envConfig.getAllowCreate());
config.setTransactional(envConfig.getTransactional());
store = new EntityStore(env, "test", config);
primary = store.getPrimaryIndex(Integer.class, MyEntity.class);
sec1 = store.getSecondaryIndex(primary, Integer.class, "k1");
sec2 = store.getSecondaryIndex(primary, Integer.class, "k2");
sec3 = store.getSecondaryIndex(primary, Integer.class, "k3");
}
/**
* Closes the store.
*/
private void close()
throws DatabaseException {
store.close();
}
public void testJoin()
throws DatabaseException {
open();
/*
* Primary keys: { 0, 1, 2, 3, 4 }
* Secondary k1: { 0:0, 0:1, 0:2, 0:3, 0:4 }
* Secondary k2: { 0:0, 1:1, 0:2, 1:3, 0:4 }
* Secondary k3: { 0:0, 1:1, 2:2, 0:3, 1:4 }
*/
Transaction txn = txnBegin();
for (int i = 0; i < N_RECORDS; i += 1) {
MyEntity e = new MyEntity(i, 0, i % 2, i % 3);
boolean ok = primary.putNoOverwrite(txn, e);
assertTrue(ok);
}
txnCommit(txn);
/*
* k1, k2, k3, -> { primary keys }
* -1 means don't include the key in the join.
*/
doJoin( 0, 0, 0, new int[] { 0 });
doJoin( 0, 0, 1, new int[] { 4 });
doJoin( 0, 0, -1, new int[] { 0, 2, 4 });
doJoin(-1, 1, 1, new int[] { 1 });
doJoin(-1, 2, 2, new int[] { });
doJoin(-1, -1, 2, new int[] { 2 });
close();
}
private void doJoin(int k1, int k2, int k3, int[] expectKeys)
throws DatabaseException {
List<Integer> expect = new ArrayList<Integer>();
for (int i : expectKeys) {
expect.add(i);
}
EntityJoin join = new EntityJoin(primary);
if (k1 >= 0) {
join.addCondition(sec1, k1);
}
if (k2 >= 0) {
join.addCondition(sec2, k2);
}
if (k3 >= 0) {
join.addCondition(sec3, k3);
}
List<Integer> found;
Transaction txn = txnBegin();
/* Keys */
found = new ArrayList<Integer>();
ForwardCursor<Integer> keys = join.keys(txn, null);
for (int i : keys) {
found.add(i);
}
keys.close();
assertEquals(expect, found);
/* Entities */
found = new ArrayList<Integer>();
ForwardCursor<MyEntity> entities = join.entities(txn, null);
for (MyEntity e : entities) {
found.add(e.id);
}
entities.close();
assertEquals(expect, found);
txnCommit(txn);
}
@Entity
private static class MyEntity {
@PrimaryKey
int id;
@SecondaryKey(relate=MANY_TO_ONE)
int k1;
@SecondaryKey(relate=MANY_TO_ONE)
int k2;
@SecondaryKey(relate=MANY_TO_ONE)
int k3;
private MyEntity() {}
MyEntity(int id, int k1, int k2, int k3) {
this.id = id;
this.k1 = k1;
this.k2 = k2;
this.k3 = k3;
}
@Override
public String toString() {
return "MyEntity " + id + ' ' + k1 + ' ' + k2 + ' ' + k3;
}
}
}

View File

@@ -0,0 +1,299 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: NegativeTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import java.util.ArrayList;
import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE;
import junit.framework.Test;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.PrimaryIndex;
import com.sleepycat.persist.StoreConfig;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.KeyField;
import com.sleepycat.persist.model.Persistent;
import com.sleepycat.persist.model.PrimaryKey;
import com.sleepycat.persist.model.SecondaryKey;
import com.sleepycat.util.test.TxnTestCase;
/**
* Negative tests.
*
* @author Mark Hayes
*/
public class NegativeTest extends TxnTestCase {
public static Test suite() {
return txnTestSuite(NegativeTest.class, null, null);
}
private EntityStore store;
private void open()
throws DatabaseException {
StoreConfig config = new StoreConfig();
config.setAllowCreate(envConfig.getAllowCreate());
config.setTransactional(envConfig.getTransactional());
store = new EntityStore(env, "test", config);
}
private void close()
throws DatabaseException {
store.close();
store = null;
}
@Override
public void tearDown()
throws Exception {
if (store != null) {
try {
store.close();
} catch (Throwable e) {
System.out.println("tearDown: " + e);
}
store = null;
}
super.tearDown();
}
public void testBadKeyClass1()
throws DatabaseException {
open();
try {
PrimaryIndex<BadKeyClass1,UseBadKeyClass1> index =
store.getPrimaryIndex
(BadKeyClass1.class, UseBadKeyClass1.class);
fail();
} catch (IllegalArgumentException expected) {
assertTrue(expected.getMessage().indexOf("@KeyField") >= 0);
}
close();
}
/** Missing @KeyField in composite key class. */
@Persistent
static class BadKeyClass1 {
private int f1;
}
@Entity
static class UseBadKeyClass1 {
@PrimaryKey
private BadKeyClass1 f1 = new BadKeyClass1();
@SecondaryKey(relate=ONE_TO_ONE)
private BadKeyClass1 f2 = new BadKeyClass1();
}
public void testBadSequenceKeys()
throws DatabaseException {
open();
try {
PrimaryIndex<Boolean,BadSequenceKeyEntity1> index =
store.getPrimaryIndex
(Boolean.class, BadSequenceKeyEntity1.class);
fail();
} catch (IllegalArgumentException expected) {
assertTrue(expected.getMessage().indexOf
("Type not allowed for sequence") >= 0);
}
try {
PrimaryIndex<BadSequenceKeyEntity2.Key,
BadSequenceKeyEntity2> index =
store.getPrimaryIndex
(BadSequenceKeyEntity2.Key.class,
BadSequenceKeyEntity2.class);
fail();
} catch (IllegalArgumentException expected) {
assertTrue(expected.getMessage().indexOf
("Type not allowed for sequence") >= 0);
}
try {
PrimaryIndex<BadSequenceKeyEntity3.Key,
BadSequenceKeyEntity3> index =
store.getPrimaryIndex
(BadSequenceKeyEntity3.Key.class,
BadSequenceKeyEntity3.class);
fail();
} catch (IllegalArgumentException expected) {
assertTrue(expected.getMessage().indexOf
("A composite key class used with a sequence may contain " +
"only a single integer key field")>= 0);
}
close();
}
/** Boolean not allowed for sequence key. */
@Entity
static class BadSequenceKeyEntity1 {
@PrimaryKey(sequence="X")
private boolean key;
}
/** Composite key with non-integer field not allowed for sequence key. */
@Entity
static class BadSequenceKeyEntity2 {
@PrimaryKey(sequence="X")
private Key key;
@Persistent
static class Key {
@KeyField(1)
boolean key;
}
}
/** Composite key with multiple key fields not allowed for sequence key. */
@Entity
static class BadSequenceKeyEntity3 {
@PrimaryKey(sequence="X")
private Key key;
@Persistent
static class Key {
@KeyField(1)
int key;
@KeyField(2)
int key2;
}
}
/**
* A proxied object may not current contain a field that references the
* parent proxy. [#15815]
*/
public void testProxyNestedRef()
throws DatabaseException {
open();
PrimaryIndex<Integer,ProxyNestedRef> index = store.getPrimaryIndex
(Integer.class, ProxyNestedRef.class);
ProxyNestedRef entity = new ProxyNestedRef();
entity.list.add(entity.list);
try {
index.put(entity);
fail();
} catch (IllegalArgumentException expected) {
assertTrue(expected.getMessage().indexOf
("Cannot embed a reference to a proxied object") >= 0);
}
close();
}
@Entity
static class ProxyNestedRef {
@PrimaryKey
private int key;
ArrayList<Object> list = new ArrayList<Object>();
}
/**
* Disallow primary keys on entity subclasses. [#15757]
*/
public void testEntitySubclassWithPrimaryKey()
throws DatabaseException {
open();
PrimaryIndex<Integer,EntitySuperClass> index = store.getPrimaryIndex
(Integer.class, EntitySuperClass.class);
EntitySuperClass e1 = new EntitySuperClass(1, "one");
index.put(e1);
assertEquals(e1, index.get(1));
EntitySubClass e2 = new EntitySubClass(2, "two", "foo", 9);
try {
index.put(e2);
} catch (IllegalArgumentException e) {
assertTrue(e.getMessage().contains
("PrimaryKey may not appear on an Entity subclass"));
}
assertEquals(e1, index.get(1));
close();
}
@Entity
static class EntitySuperClass {
@PrimaryKey
private int x;
private String y;
EntitySuperClass(int x, String y) {
assert y != null;
this.x = x;
this.y = y;
}
private EntitySuperClass() {}
@Override
public String toString() {
return "x=" + x + " y=" + y;
}
@Override
public boolean equals(Object other) {
if (other instanceof EntitySuperClass) {
EntitySuperClass o = (EntitySuperClass) other;
return x == o.x && y.equals(o.y);
} else {
return false;
}
}
}
@Persistent
static class EntitySubClass extends EntitySuperClass {
@PrimaryKey
private String foo;
private int z;
EntitySubClass(int x, String y, String foo, int z) {
super(x, y);
assert foo != null;
this.foo = foo;
this.z = z;
}
private EntitySubClass() {}
@Override
public String toString() {
return super.toString() + " z=" + z;
}
@Override
public boolean equals(Object other) {
if (other instanceof EntitySubClass) {
EntitySubClass o = (EntitySubClass) other;
return super.equals(o) && z == o.z;
} else {
return false;
}
}
}
}

View File

@@ -0,0 +1,879 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: OperationTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
import static com.sleepycat.persist.model.Relationship.ONE_TO_MANY;
import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE;
import static com.sleepycat.persist.model.DeleteAction.CASCADE;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import junit.framework.Test;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Transaction;
import com.sleepycat.persist.EntityCursor;
import com.sleepycat.persist.EntityIndex;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.PrimaryIndex;
import com.sleepycat.persist.SecondaryIndex;
import com.sleepycat.persist.StoreConfig;
import com.sleepycat.persist.impl.Store;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.KeyField;
import com.sleepycat.persist.model.Persistent;
import com.sleepycat.persist.model.PrimaryKey;
import com.sleepycat.persist.model.SecondaryKey;
import com.sleepycat.persist.raw.RawStore;
import com.sleepycat.util.test.TxnTestCase;
/**
* Tests misc store and index operations that are not tested by IndexTest.
*
* @author Mark Hayes
*/
public class OperationTest extends TxnTestCase {
private static final String STORE_NAME = "test";
public static Test suite() {
return txnTestSuite(OperationTest.class, null, null);
}
private EntityStore store;
private void openReadOnly()
throws DatabaseException {
StoreConfig config = new StoreConfig();
config.setReadOnly(true);
open(config);
}
private void open()
throws DatabaseException {
StoreConfig config = new StoreConfig();
config.setAllowCreate(envConfig.getAllowCreate());
open(config);
}
private void open(StoreConfig config)
throws DatabaseException {
config.setTransactional(envConfig.getTransactional());
store = new EntityStore(env, STORE_NAME, config);
}
private void close()
throws DatabaseException {
store.close();
store = null;
}
/**
* The store must be closed before closing the environment.
*/
public void tearDown()
throws Exception {
try {
if (store != null) {
store.close();
}
} catch (Throwable e) {
System.out.println("During tearDown: " + e);
}
store = null;
super.tearDown();
}
public void testReadOnly()
throws DatabaseException {
open();
PrimaryIndex<Integer,SharedSequenceEntity1> priIndex =
store.getPrimaryIndex(Integer.class, SharedSequenceEntity1.class);
Transaction txn = txnBegin();
SharedSequenceEntity1 e = new SharedSequenceEntity1();
priIndex.put(txn, e);
assertEquals(1, e.key);
txnCommit(txn);
close();
/*
* Check that we can open the store read-only and read the records
* written above.
*/
openReadOnly();
priIndex =
store.getPrimaryIndex(Integer.class, SharedSequenceEntity1.class);
e = priIndex.get(1);
assertNotNull(e);
close();
}
public void testUninitializedCursor()
throws DatabaseException {
open();
PrimaryIndex<Integer,MyEntity> priIndex =
store.getPrimaryIndex(Integer.class, MyEntity.class);
Transaction txn = txnBeginCursor();
MyEntity e = new MyEntity();
e.priKey = 1;
e.secKey = 1;
priIndex.put(txn, e);
EntityCursor<MyEntity> entities = priIndex.entities(txn, null);
try {
entities.nextDup();
fail();
} catch (IllegalStateException expected) {}
try {
entities.prevDup();
fail();
} catch (IllegalStateException expected) {}
try {
entities.current();
fail();
} catch (IllegalStateException expected) {}
try {
entities.delete();
fail();
} catch (IllegalStateException expected) {}
try {
entities.update(e);
fail();
} catch (IllegalStateException expected) {}
try {
entities.count();
fail();
} catch (IllegalStateException expected) {}
entities.close();
txnCommit(txn);
close();
}
public void testCursorCount()
throws DatabaseException {
open();
PrimaryIndex<Integer,MyEntity> priIndex =
store.getPrimaryIndex(Integer.class, MyEntity.class);
SecondaryIndex<Integer,Integer,MyEntity> secIndex =
store.getSecondaryIndex(priIndex, Integer.class, "secKey");
Transaction txn = txnBeginCursor();
MyEntity e = new MyEntity();
e.priKey = 1;
e.secKey = 1;
priIndex.put(txn, e);
EntityCursor<MyEntity> cursor = secIndex.entities(txn, null);
cursor.next();
assertEquals(1, cursor.count());
cursor.close();
e.priKey = 2;
priIndex.put(txn, e);
cursor = secIndex.entities(txn, null);
cursor.next();
assertEquals(2, cursor.count());
cursor.close();
txnCommit(txn);
close();
}
public void testCursorUpdate()
throws DatabaseException {
open();
PrimaryIndex<Integer,MyEntity> priIndex =
store.getPrimaryIndex(Integer.class, MyEntity.class);
SecondaryIndex<Integer,Integer,MyEntity> secIndex =
store.getSecondaryIndex(priIndex, Integer.class, "secKey");
Transaction txn = txnBeginCursor();
Integer k;
MyEntity e = new MyEntity();
e.priKey = 1;
e.secKey = 2;
priIndex.put(txn, e);
/* update() with primary entity cursor. */
EntityCursor<MyEntity> entities = priIndex.entities(txn, null);
e = entities.next();
assertNotNull(e);
assertEquals(1, e.priKey);
assertEquals(Integer.valueOf(2), e.secKey);
e.secKey = null;
assertTrue(entities.update(e));
e = entities.current();
assertNotNull(e);
assertEquals(1, e.priKey);
assertEquals(null, e.secKey);
e.secKey = 3;
assertTrue(entities.update(e));
e = entities.current();
assertNotNull(e);
assertEquals(1, e.priKey);
assertEquals(Integer.valueOf(3), e.secKey);
entities.close();
/* update() with primary keys cursor. */
EntityCursor<Integer> keys = priIndex.keys(txn, null);
k = keys.next();
assertNotNull(k);
assertEquals(Integer.valueOf(1), k);
try {
keys.update(2);
fail();
} catch (UnsupportedOperationException expected) {
}
keys.close();
/* update() with secondary entity cursor. */
entities = secIndex.entities(txn, null);
e = entities.next();
assertNotNull(e);
assertEquals(1, e.priKey);
assertEquals(Integer.valueOf(3), e.secKey);
try {
entities.update(e);
fail();
} catch (UnsupportedOperationException expected) {
} catch (IllegalArgumentException expectedForDbCore) {
}
entities.close();
/* update() with secondary keys cursor. */
keys = secIndex.keys(txn, null);
k = keys.next();
assertNotNull(k);
assertEquals(Integer.valueOf(3), k);
try {
keys.update(k);
fail();
} catch (UnsupportedOperationException expected) {
}
keys.close();
txnCommit(txn);
close();
}
public void testCursorDelete()
throws DatabaseException {
open();
PrimaryIndex<Integer,MyEntity> priIndex =
store.getPrimaryIndex(Integer.class, MyEntity.class);
SecondaryIndex<Integer,Integer,MyEntity> secIndex =
store.getSecondaryIndex(priIndex, Integer.class, "secKey");
Transaction txn = txnBeginCursor();
/* delete() with primary and secondary entities cursor. */
for (EntityIndex index : new EntityIndex[] { priIndex, secIndex }) {
MyEntity e = new MyEntity();
e.priKey = 1;
e.secKey = 1;
priIndex.put(txn, e);
e.priKey = 2;
priIndex.put(txn, e);
EntityCursor<MyEntity> cursor = index.entities(txn, null);
e = cursor.next();
assertNotNull(e);
assertEquals(1, e.priKey);
e = cursor.current();
assertNotNull(e);
assertEquals(1, e.priKey);
assertTrue(cursor.delete());
assertTrue(!cursor.delete());
assertNull(cursor.current());
e = cursor.next();
assertNotNull(e);
assertEquals(2, e.priKey);
e = cursor.current();
assertNotNull(e);
assertEquals(2, e.priKey);
assertTrue(cursor.delete());
assertTrue(!cursor.delete());
assertNull(cursor.current());
e = cursor.next();
assertNull(e);
if (index == priIndex) {
e = new MyEntity();
e.priKey = 2;
e.secKey = 1;
assertTrue(!cursor.update(e));
}
cursor.close();
}
/* delete() with primary and secondary keys cursor. */
for (EntityIndex index : new EntityIndex[] { priIndex, secIndex }) {
MyEntity e = new MyEntity();
e.priKey = 1;
e.secKey = 1;
priIndex.put(txn, e);
e.priKey = 2;
priIndex.put(txn, e);
EntityCursor<Integer> cursor = index.keys(txn, null);
Integer k = cursor.next();
assertNotNull(k);
assertEquals(1, k.intValue());
k = cursor.current();
assertNotNull(k);
assertEquals(1, k.intValue());
assertTrue(cursor.delete());
assertTrue(!cursor.delete());
assertNull(cursor.current());
int expectKey = (index == priIndex) ? 2 : 1;
k = cursor.next();
assertNotNull(k);
assertEquals(expectKey, k.intValue());
k = cursor.current();
assertNotNull(k);
assertEquals(expectKey, k.intValue());
assertTrue(cursor.delete());
assertTrue(!cursor.delete());
assertNull(cursor.current());
k = cursor.next();
assertNull(k);
cursor.close();
}
txnCommit(txn);
close();
}
public void testDeleteFromSubIndex()
throws DatabaseException {
open();
PrimaryIndex<Integer,MyEntity> priIndex =
store.getPrimaryIndex(Integer.class, MyEntity.class);
SecondaryIndex<Integer,Integer,MyEntity> secIndex =
store.getSecondaryIndex(priIndex, Integer.class, "secKey");
Transaction txn = txnBegin();
MyEntity e = new MyEntity();
e.secKey = 1;
e.priKey = 1;
priIndex.put(txn, e);
e.priKey = 2;
priIndex.put(txn, e);
e.priKey = 3;
priIndex.put(txn, e);
e.priKey = 4;
priIndex.put(txn, e);
txnCommit(txn);
EntityIndex<Integer,MyEntity> subIndex = secIndex.subIndex(1);
txn = txnBeginCursor();
e = subIndex.get(txn, 1, null);
assertEquals(1, e.priKey);
assertEquals(Integer.valueOf(1), e.secKey);
e = subIndex.get(txn, 2, null);
assertEquals(2, e.priKey);
assertEquals(Integer.valueOf(1), e.secKey);
e = subIndex.get(txn, 3, null);
assertEquals(3, e.priKey);
assertEquals(Integer.valueOf(1), e.secKey);
e = subIndex.get(txn, 5, null);
assertNull(e);
boolean deleted = subIndex.delete(txn, 1);
assertTrue(deleted);
assertNull(subIndex.get(txn, 1, null));
assertNotNull(subIndex.get(txn, 2, null));
EntityCursor<MyEntity> cursor = subIndex.entities(txn, null);
boolean saw4 = false;
for (MyEntity e2 = cursor.first(); e2 != null; e2 = cursor.next()) {
if (e2.priKey == 3) {
cursor.delete();
}
if (e2.priKey == 4) {
saw4 = true;
}
}
cursor.close();
assertTrue(saw4);
assertNull(subIndex.get(txn, 1, null));
assertNull(subIndex.get(txn, 3, null));
assertNotNull(subIndex.get(txn, 2, null));
assertNotNull(subIndex.get(txn, 4, null));
txnCommit(txn);
close();
}
@Entity
static class MyEntity {
@PrimaryKey
private int priKey;
@SecondaryKey(relate=MANY_TO_ONE)
private Integer secKey;
private MyEntity() {}
}
public void testSharedSequence()
throws DatabaseException {
open();
PrimaryIndex<Integer,SharedSequenceEntity1> priIndex1 =
store.getPrimaryIndex(Integer.class, SharedSequenceEntity1.class);
PrimaryIndex<Integer,SharedSequenceEntity2> priIndex2 =
store.getPrimaryIndex(Integer.class, SharedSequenceEntity2.class);
Transaction txn = txnBegin();
SharedSequenceEntity1 e1 = new SharedSequenceEntity1();
SharedSequenceEntity2 e2 = new SharedSequenceEntity2();
priIndex1.put(txn, e1);
assertEquals(1, e1.key);
priIndex2.putNoOverwrite(txn, e2);
assertEquals(Integer.valueOf(2), e2.key);
e1.key = 0;
priIndex1.putNoOverwrite(txn, e1);
assertEquals(3, e1.key);
e2.key = null;
priIndex2.put(txn, e2);
assertEquals(Integer.valueOf(4), e2.key);
txnCommit(txn);
close();
}
@Entity
static class SharedSequenceEntity1 {
@PrimaryKey(sequence="shared")
private int key;
}
@Entity
static class SharedSequenceEntity2 {
@PrimaryKey(sequence="shared")
private Integer key;
}
public void testSeparateSequence()
throws DatabaseException {
open();
PrimaryIndex<Integer,SeparateSequenceEntity1> priIndex1 =
store.getPrimaryIndex
(Integer.class, SeparateSequenceEntity1.class);
PrimaryIndex<Integer,SeparateSequenceEntity2> priIndex2 =
store.getPrimaryIndex
(Integer.class, SeparateSequenceEntity2.class);
Transaction txn = txnBegin();
SeparateSequenceEntity1 e1 = new SeparateSequenceEntity1();
SeparateSequenceEntity2 e2 = new SeparateSequenceEntity2();
priIndex1.put(txn, e1);
assertEquals(1, e1.key);
priIndex2.putNoOverwrite(txn, e2);
assertEquals(Integer.valueOf(1), e2.key);
e1.key = 0;
priIndex1.putNoOverwrite(txn, e1);
assertEquals(2, e1.key);
e2.key = null;
priIndex2.put(txn, e2);
assertEquals(Integer.valueOf(2), e2.key);
txnCommit(txn);
close();
}
@Entity
static class SeparateSequenceEntity1 {
@PrimaryKey(sequence="seq1")
private int key;
}
@Entity
static class SeparateSequenceEntity2 {
@PrimaryKey(sequence="seq2")
private Integer key;
}
public void testCompositeSequence()
throws DatabaseException {
open();
PrimaryIndex<CompositeSequenceEntity1.Key,CompositeSequenceEntity1>
priIndex1 =
store.getPrimaryIndex
(CompositeSequenceEntity1.Key.class,
CompositeSequenceEntity1.class);
PrimaryIndex<CompositeSequenceEntity2.Key,CompositeSequenceEntity2>
priIndex2 =
store.getPrimaryIndex
(CompositeSequenceEntity2.Key.class,
CompositeSequenceEntity2.class);
Transaction txn = txnBegin();
CompositeSequenceEntity1 e1 = new CompositeSequenceEntity1();
CompositeSequenceEntity2 e2 = new CompositeSequenceEntity2();
priIndex1.put(txn, e1);
assertEquals(1, e1.key.key);
priIndex2.putNoOverwrite(txn, e2);
assertEquals(Integer.valueOf(1), e2.key.key);
e1.key = null;
priIndex1.putNoOverwrite(txn, e1);
assertEquals(2, e1.key.key);
e2.key = null;
priIndex2.put(txn, e2);
assertEquals(Integer.valueOf(2), e2.key.key);
txnCommit(txn);
EntityCursor<CompositeSequenceEntity1> c1 = priIndex1.entities();
e1 = c1.next();
assertEquals(2, e1.key.key);
e1 = c1.next();
assertEquals(1, e1.key.key);
e1 = c1.next();
assertNull(e1);
c1.close();
EntityCursor<CompositeSequenceEntity2> c2 = priIndex2.entities();
e2 = c2.next();
assertEquals(Integer.valueOf(2), e2.key.key);
e2 = c2.next();
assertEquals(Integer.valueOf(1), e2.key.key);
e2 = c2.next();
assertNull(e2);
c2.close();
close();
}
@Entity
static class CompositeSequenceEntity1 {
@Persistent
static class Key implements Comparable<Key> {
@KeyField(1)
private int key;
public int compareTo(Key o) {
/* Reverse the natural order. */
return o.key - key;
}
}
@PrimaryKey(sequence="seq1")
private Key key;
}
@Entity
static class CompositeSequenceEntity2 {
@Persistent
static class Key implements Comparable<Key> {
@KeyField(1)
private Integer key;
public int compareTo(Key o) {
/* Reverse the natural order. */
return o.key - key;
}
}
@PrimaryKey(sequence="seq2")
private Key key;
}
/**
* When opening read-only, secondaries are not opened when the primary is
* opened, causing a different code path to be used for opening
* secondaries. For a RawStore in particular, this caused an unreported
* NullPointerException in JE 3.0.12. No SR was created because the use
* case is very obscure and was discovered by code inspection.
*/
public void testOpenRawStoreReadOnly()
throws DatabaseException {
open();
store.getPrimaryIndex(Integer.class, MyEntity.class);
close();
StoreConfig config = new StoreConfig();
config.setReadOnly(true);
config.setTransactional(envConfig.getTransactional());
RawStore rawStore = new RawStore(env, "test", config);
String clsName = MyEntity.class.getName();
rawStore.getSecondaryIndex(clsName, "secKey");
rawStore.close();
}
/**
* When opening an X_TO_MANY secondary that has a persistent key class, the
* key class was not recognized as being persistent if it was never before
* referenced when getSecondaryIndex was called. This was a bug in JE
* 3.0.12, reported on OTN. [#15103]
*/
public void testToManyKeyClass()
throws DatabaseException {
open();
PrimaryIndex<Integer,ToManyKeyEntity> priIndex =
store.getPrimaryIndex(Integer.class, ToManyKeyEntity.class);
SecondaryIndex<ToManyKey,Integer,ToManyKeyEntity> secIndex =
store.getSecondaryIndex(priIndex, ToManyKey.class, "key2");
priIndex.put(new ToManyKeyEntity());
secIndex.get(new ToManyKey());
close();
}
/**
* Test a fix for a bug where opening a TO_MANY secondary index would fail
* fail with "IllegalArgumentException: Wrong secondary key class: ..."
* when the store was opened read-only. [#15156]
*/
public void testToManyReadOnly()
throws DatabaseException {
open();
PrimaryIndex<Integer,ToManyKeyEntity> priIndex =
store.getPrimaryIndex(Integer.class, ToManyKeyEntity.class);
priIndex.put(new ToManyKeyEntity());
close();
openReadOnly();
priIndex = store.getPrimaryIndex(Integer.class, ToManyKeyEntity.class);
SecondaryIndex<ToManyKey,Integer,ToManyKeyEntity> secIndex =
store.getSecondaryIndex(priIndex, ToManyKey.class, "key2");
secIndex.get(new ToManyKey());
close();
}
@Persistent
static class ToManyKey {
@KeyField(1)
int value = 99;
}
@Entity
static class ToManyKeyEntity {
@PrimaryKey
int key = 88;
@SecondaryKey(relate=ONE_TO_MANY)
Set<ToManyKey> key2;
ToManyKeyEntity() {
key2 = new HashSet<ToManyKey>();
key2.add(new ToManyKey());
}
}
/**
* When Y is opened and X has a key with relatedEntity=Y.class, X should
* be opened automatically. If X is not opened, foreign key constraints
* will not be enforced. [#15358]
*/
public void testAutoOpenRelatedEntity()
throws DatabaseException {
PrimaryIndex<Integer,RelatedY> priY;
PrimaryIndex<Integer,RelatedX> priX;
/* Opening X should create (and open) Y and enforce constraints. */
open();
priX = store.getPrimaryIndex(Integer.class, RelatedX.class);
PersistTestUtils.assertDbExists
(true, env, STORE_NAME, RelatedY.class.getName(), null);
try {
priX.put(new RelatedX());
fail();
} catch (DatabaseException e) {
assertTrue
("" + e.getMessage(), (e.getMessage().indexOf
("foreign key not allowed: it is not present") >= 0) ||
(e.getMessage().indexOf("DB_FOREIGN_CONFLICT") >= 0));
}
priY = store.getPrimaryIndex(Integer.class, RelatedY.class);
priY.put(new RelatedY());
priX.put(new RelatedX());
close();
/* Delete should cascade even when X is not opened explicitly. */
open();
priY = store.getPrimaryIndex(Integer.class, RelatedY.class);
assertEquals(1, priY.count());
priY.delete(88);
assertEquals(0, priY.count());
priX = store.getPrimaryIndex(Integer.class, RelatedX.class);
assertEquals(0, priX.count()); /* Failed prior to [#15358] fix. */
close();
}
@Entity
static class RelatedX {
@PrimaryKey
int key = 99;
@SecondaryKey(relate=ONE_TO_ONE,
relatedEntity=RelatedY.class,
onRelatedEntityDelete=CASCADE)
int key2 = 88;
RelatedX() {
}
}
@Entity
static class RelatedY {
@PrimaryKey
int key = 88;
RelatedY() {
}
}
public void testSecondaryBulkLoad1()
throws DatabaseException {
doSecondaryBulkLoad(true);
}
public void testSecondaryBulkLoad2()
throws DatabaseException {
doSecondaryBulkLoad(false);
}
private void doSecondaryBulkLoad(boolean closeAndOpenNormally)
throws DatabaseException {
PrimaryIndex<Integer,RelatedX> priX;
PrimaryIndex<Integer,RelatedY> priY;
SecondaryIndex<Integer,Integer,RelatedX> secX;
/* Open priX with SecondaryBulkLoad=true. */
StoreConfig config = new StoreConfig();
config.setAllowCreate(true);
config.setSecondaryBulkLoad(true);
open(config);
/* Getting priX should not create the secondary index. */
priX = store.getPrimaryIndex(Integer.class, RelatedX.class);
PersistTestUtils.assertDbExists
(false, env, STORE_NAME, RelatedX.class.getName(), "key2");
/* We can put records that violate the secondary key constraint. */
priX.put(new RelatedX());
if (closeAndOpenNormally) {
/* Open normally and the secondary will be populated. */
close();
open();
try {
/* Before adding the foreign key, constraint is violated. */
priX = store.getPrimaryIndex(Integer.class, RelatedX.class);
} catch (DatabaseException e) {
assertTrue(e.toString(),
e.toString().contains("foreign key not allowed"));
}
/* Add the foreign key to avoid the constraint error. */
priY = store.getPrimaryIndex(Integer.class, RelatedY.class);
priY.put(new RelatedY());
priX = store.getPrimaryIndex(Integer.class, RelatedX.class);
PersistTestUtils.assertDbExists
(true, env, STORE_NAME, RelatedX.class.getName(), "key2");
secX = store.getSecondaryIndex(priX, Integer.class, "key2");
} else {
/* Get secondary index explicitly and it will be populated. */
try {
/* Before adding the foreign key, constraint is violated. */
secX = store.getSecondaryIndex(priX, Integer.class, "key2");
} catch (DatabaseException e) {
assertTrue(e.toString(),
e.toString().contains("foreign key not allowed"));
}
/* Add the foreign key. */
priY = store.getPrimaryIndex(Integer.class, RelatedY.class);
priY.put(new RelatedY());
secX = store.getSecondaryIndex(priX, Integer.class, "key2");
PersistTestUtils.assertDbExists
(true, env, STORE_NAME, RelatedX.class.getName(), "key2");
}
RelatedX x = secX.get(88);
assertNotNull(x);
close();
}
}

View File

@@ -0,0 +1,66 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000,2008 Oracle. All rights reserved.
*
* $Id: PersistTestUtils.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import java.io.FileNotFoundException;
import junit.framework.TestCase;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.Database;
import com.sleepycat.db.DatabaseConfig;
import com.sleepycat.db.Environment;
class PersistTestUtils {
/**
* Asserts than a database expectExists or does not exist. If keyName is
* null, checks an entity database. If keyName is non-null, checks a
* secondary database.
*/
static void assertDbExists(boolean expectExists,
Environment env,
String storeName,
String entityClassName,
String keyName) {
String fileName;
String dbName;
if (DbCompat.SEPARATE_DATABASE_FILES) {
fileName = storeName + '-' + entityClassName;
if (keyName != null) {
fileName += "-" + keyName;
}
dbName = null;
} else {
fileName = null;
dbName = "persist#" + storeName + '#' + entityClassName;
if (keyName != null) {
dbName += "#" + keyName;
}
}
boolean exists;
try {
DatabaseConfig config = new DatabaseConfig();
config.setReadOnly(true);
Database db = DbCompat.openDatabase
(env, null/*txn*/, fileName, dbName, config);
db.close();
exists = true;
} catch (FileNotFoundException e) {
exists = false;
} catch (Exception e) {
/* Any other exception means the DB does exist. */
exists = true;
}
if (expectExists != exists) {
TestCase.fail
((expectExists ? "Does not exist: " : "Does exist: ") +
dbName);
}
}
}

View File

@@ -0,0 +1,477 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: SequenceTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import java.io.File;
import java.io.IOException;
import junit.framework.TestCase;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.PrimaryIndex;
import com.sleepycat.persist.StoreConfig;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.KeyField;
import com.sleepycat.persist.model.Persistent;
import com.sleepycat.persist.model.PrimaryKey;
import com.sleepycat.util.test.SharedTestUtils;
import com.sleepycat.util.test.TestEnv;
/**
* @author Mark Hayes
*/
public class SequenceTest extends TestCase {
private File envHome;
private Environment env;
public void setUp()
throws IOException {
envHome = new File(System.getProperty(SharedTestUtils.DEST_DIR));
SharedTestUtils.emptyDir(envHome);
}
public void tearDown()
throws IOException {
if (env != null) {
try {
env.close();
} catch (DatabaseException e) {
System.out.println("During tearDown: " + e);
}
}
try {
SharedTestUtils.emptyDir(envHome);
} catch (Error e) {
System.out.println("During tearDown: " + e);
}
envHome = null;
env = null;
}
public void testSequenceKeys()
throws Exception {
Class[] classes = {
SequenceEntity_Long.class,
SequenceEntity_Integer.class,
SequenceEntity_Short.class,
SequenceEntity_Byte.class,
SequenceEntity_tlong.class,
SequenceEntity_tint.class,
SequenceEntity_tshort.class,
SequenceEntity_tbyte.class,
SequenceEntity_Long_composite.class,
SequenceEntity_Integer_composite.class,
SequenceEntity_Short_composite.class,
SequenceEntity_Byte_composite.class,
SequenceEntity_tlong_composite.class,
SequenceEntity_tint_composite.class,
SequenceEntity_tshort_composite.class,
SequenceEntity_tbyte_composite.class,
};
EnvironmentConfig envConfig = TestEnv.BDB.getConfig();
envConfig.setAllowCreate(true);
env = new Environment(envHome, envConfig);
StoreConfig storeConfig = new StoreConfig();
storeConfig.setAllowCreate(true);
EntityStore store = new EntityStore(env, "foo", storeConfig);
long seq = 0;
for (int i = 0; i < classes.length; i += 1) {
Class entityCls = classes[i];
SequenceEntity entity = (SequenceEntity) entityCls.newInstance();
Class keyCls = entity.getKeyClass();
PrimaryIndex<Object,SequenceEntity> index =
store.getPrimaryIndex(keyCls, entityCls);
index.putNoReturn(entity);
seq += 1;
assertEquals(seq, entity.getKey());
index.putNoReturn(entity);
assertEquals(seq, entity.getKey());
entity.nullifyKey();
index.putNoReturn(entity);
seq += 1;
assertEquals(seq, entity.getKey());
}
store.close();
env.close();
env = null;
}
interface SequenceEntity {
Class getKeyClass();
long getKey();
void nullifyKey();
}
@Entity
static class SequenceEntity_Long implements SequenceEntity {
@PrimaryKey(sequence="X")
Long priKey;
public Class getKeyClass() {
return Long.class;
}
public long getKey() {
return priKey;
}
public void nullifyKey() {
priKey = null;
}
}
@Entity
static class SequenceEntity_Integer implements SequenceEntity {
@PrimaryKey(sequence="X")
Integer priKey;
public Class getKeyClass() {
return Integer.class;
}
public long getKey() {
return priKey;
}
public void nullifyKey() {
priKey = null;
}
}
@Entity
static class SequenceEntity_Short implements SequenceEntity {
@PrimaryKey(sequence="X")
Short priKey;
public Class getKeyClass() {
return Short.class;
}
public long getKey() {
return priKey;
}
public void nullifyKey() {
priKey = null;
}
}
@Entity
static class SequenceEntity_Byte implements SequenceEntity {
@PrimaryKey(sequence="X")
Byte priKey;
public Class getKeyClass() {
return Byte.class;
}
public long getKey() {
return priKey;
}
public void nullifyKey() {
priKey = null;
}
}
@Entity
static class SequenceEntity_tlong implements SequenceEntity {
@PrimaryKey(sequence="X")
long priKey;
public Class getKeyClass() {
return Long.class;
}
public long getKey() {
return priKey;
}
public void nullifyKey() {
priKey = 0;
}
}
@Entity
static class SequenceEntity_tint implements SequenceEntity {
@PrimaryKey(sequence="X")
int priKey;
public Class getKeyClass() {
return Integer.class;
}
public long getKey() {
return priKey;
}
public void nullifyKey() {
priKey = 0;
}
}
@Entity
static class SequenceEntity_tshort implements SequenceEntity {
@PrimaryKey(sequence="X")
short priKey;
public Class getKeyClass() {
return Short.class;
}
public long getKey() {
return priKey;
}
public void nullifyKey() {
priKey = 0;
}
}
@Entity
static class SequenceEntity_tbyte implements SequenceEntity {
@PrimaryKey(sequence="X")
byte priKey;
public Class getKeyClass() {
return Byte.class;
}
public long getKey() {
return priKey;
}
public void nullifyKey() {
priKey = 0;
}
}
@Entity
static class SequenceEntity_Long_composite implements SequenceEntity {
@PrimaryKey(sequence="X")
Key priKey;
@Persistent
static class Key {
@KeyField(1)
Long priKey;
}
public Class getKeyClass() {
return Key.class;
}
public long getKey() {
return priKey.priKey;
}
public void nullifyKey() {
priKey = null;
}
}
@Entity
static class SequenceEntity_Integer_composite implements SequenceEntity {
@PrimaryKey(sequence="X")
Key priKey;
@Persistent
static class Key {
@KeyField(1)
Integer priKey;
}
public Class getKeyClass() {
return Key.class;
}
public long getKey() {
return priKey.priKey;
}
public void nullifyKey() {
priKey = null;
}
}
@Entity
static class SequenceEntity_Short_composite implements SequenceEntity {
@PrimaryKey(sequence="X")
Key priKey;
@Persistent
static class Key {
@KeyField(1)
Short priKey;
}
public Class getKeyClass() {
return Key.class;
}
public long getKey() {
return priKey.priKey;
}
public void nullifyKey() {
priKey = null;
}
}
@Entity
static class SequenceEntity_Byte_composite implements SequenceEntity {
@PrimaryKey(sequence="X")
Key priKey;
@Persistent
static class Key {
@KeyField(1)
Byte priKey;
}
public Class getKeyClass() {
return Key.class;
}
public long getKey() {
return priKey.priKey;
}
public void nullifyKey() {
priKey = null;
}
}
@Entity
static class SequenceEntity_tlong_composite implements SequenceEntity {
@PrimaryKey(sequence="X")
Key priKey;
@Persistent
static class Key {
@KeyField(1)
long priKey;
}
public Class getKeyClass() {
return Key.class;
}
public long getKey() {
return priKey.priKey;
}
public void nullifyKey() {
priKey = null;
}
}
@Entity
static class SequenceEntity_tint_composite implements SequenceEntity {
@PrimaryKey(sequence="X")
Key priKey;
@Persistent
static class Key {
@KeyField(1)
int priKey;
}
public Class getKeyClass() {
return Key.class;
}
public long getKey() {
return priKey.priKey;
}
public void nullifyKey() {
priKey = null;
}
}
@Entity
static class SequenceEntity_tshort_composite implements SequenceEntity {
@PrimaryKey(sequence="X")
Key priKey;
@Persistent
static class Key {
@KeyField(1)
short priKey;
}
public Class getKeyClass() {
return Key.class;
}
public long getKey() {
return priKey.priKey;
}
public void nullifyKey() {
priKey = null;
}
}
@Entity
static class SequenceEntity_tbyte_composite implements SequenceEntity {
@PrimaryKey(sequence="X")
Key priKey;
@Persistent
static class Key {
@KeyField(1)
byte priKey;
}
public Class getKeyClass() {
return Key.class;
}
public long getKey() {
return priKey.priKey;
}
public void nullifyKey() {
priKey = null;
}
}
}

View File

@@ -0,0 +1,170 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: SubclassIndexTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.persist.test;
import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE;
import java.io.File;
import java.io.IOException;
import junit.framework.TestCase;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
import com.sleepycat.persist.EntityCursor;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.PrimaryIndex;
import com.sleepycat.persist.SecondaryIndex;
import com.sleepycat.persist.StoreConfig;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.Persistent;
import com.sleepycat.persist.model.PrimaryKey;
import com.sleepycat.persist.model.SecondaryKey;
import com.sleepycat.util.test.SharedTestUtils;
import com.sleepycat.util.test.TestEnv;
public class SubclassIndexTest extends TestCase {
private File envHome;
private Environment env;
public void setUp()
throws IOException {
envHome = new File(System.getProperty(SharedTestUtils.DEST_DIR));
SharedTestUtils.emptyDir(envHome);
}
public void tearDown()
throws IOException {
if (env != null) {
try {
env.close();
} catch (DatabaseException e) {
System.out.println("During tearDown: " + e);
}
}
try {
SharedTestUtils.emptyDir(envHome);
} catch (Error e) {
System.out.println("During tearDown: " + e);
}
envHome = null;
env = null;
}
public void testSubclassIndex()
throws IOException, DatabaseException {
EnvironmentConfig envConfig = TestEnv.BDB.getConfig();
envConfig.setAllowCreate(true);
env = new Environment(envHome, envConfig);
StoreConfig storeConfig = new StoreConfig();
storeConfig.setAllowCreate(true);
EntityStore store = new EntityStore(env, "foo", storeConfig);
PrimaryIndex<String, Employee> employeesById =
store.getPrimaryIndex(String.class, Employee.class);
employeesById.put(new Employee("1"));
employeesById.put(new Manager("2", "a"));
employeesById.put(new Manager("3", "a"));
employeesById.put(new Manager("4", "b"));
Employee e;
Manager m;
e = employeesById.get("1");
assertNotNull(e);
assertTrue(!(e instanceof Manager));
/* Ensure DB exists BEFORE calling getSubclassIndex. [#15247] */
PersistTestUtils.assertDbExists
(true, env, "foo", Employee.class.getName(), "dept");
/* Normal use: Subclass index for a key in the subclass. */
SecondaryIndex<String, String, Manager> managersByDept =
store.getSubclassIndex
(employeesById, Manager.class, String.class, "dept");
m = managersByDept.get("a");
assertNotNull(m);
assertEquals("2", m.id);
m = managersByDept.get("b");
assertNotNull(m);
assertEquals("4", m.id);
EntityCursor<Manager> managers = managersByDept.entities();
try {
m = managers.next();
assertNotNull(m);
assertEquals("2", m.id);
m = managers.next();
assertNotNull(m);
assertEquals("3", m.id);
m = managers.next();
assertNotNull(m);
assertEquals("4", m.id);
m = managers.next();
assertNull(m);
} finally {
managers.close();
}
/* Getting a subclass index for the entity class is also allowed. */
store.getSubclassIndex
(employeesById, Employee.class, String.class, "other");
/* Getting a subclass index for a base class key is not allowed. */
try {
store.getSubclassIndex
(employeesById, Manager.class, String.class, "other");
fail();
} catch (IllegalArgumentException expected) {
}
store.close();
env.close();
env = null;
}
@Entity
private static class Employee {
@PrimaryKey
String id;
@SecondaryKey(relate=MANY_TO_ONE)
String other;
Employee(String id) {
this.id = id;
}
private Employee() {}
}
@Persistent
private static class Manager extends Employee {
@SecondaryKey(relate=MANY_TO_ONE)
String dept;
Manager(String id, String dept) {
super(id);
this.dept = dept;
}
private Manager() {}
}
}

View File

@@ -0,0 +1,144 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: ExceptionWrapperTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.util.test;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.util.ExceptionUnwrapper;
import com.sleepycat.util.IOExceptionWrapper;
import com.sleepycat.util.RuntimeExceptionWrapper;
import com.sleepycat.util.test.SharedTestUtils;
/**
* @author Mark Hayes
*/
public class ExceptionWrapperTest extends TestCase {
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite(ExceptionWrapperTest.class);
return suite;
}
public ExceptionWrapperTest(String name) {
super(name);
}
public void setUp() {
SharedTestUtils.printTestName("ExceptionWrapperTest." + getName());
}
public void testIOWrapper()
throws Exception {
try {
throw new IOExceptionWrapper(new RuntimeException("msg"));
} catch (IOException e) {
Exception ee = ExceptionUnwrapper.unwrap(e);
assertTrue(ee instanceof RuntimeException);
assertEquals("msg", ee.getMessage());
Throwable t = ExceptionUnwrapper.unwrapAny(e);
assertTrue(t instanceof RuntimeException);
assertEquals("msg", t.getMessage());
}
}
public void testRuntimeWrapper()
throws Exception {
try {
throw new RuntimeExceptionWrapper(new IOException("msg"));
} catch (RuntimeException e) {
Exception ee = ExceptionUnwrapper.unwrap(e);
assertTrue(ee instanceof IOException);
assertEquals("msg", ee.getMessage());
Throwable t = ExceptionUnwrapper.unwrapAny(e);
assertTrue(t instanceof IOException);
assertEquals("msg", t.getMessage());
}
}
public void testErrorWrapper()
throws Exception {
try {
throw new RuntimeExceptionWrapper(new Error("msg"));
} catch (RuntimeException e) {
try {
ExceptionUnwrapper.unwrap(e);
fail();
} catch (Error ee) {
assertTrue(ee instanceof Error);
assertEquals("msg", ee.getMessage());
}
Throwable t = ExceptionUnwrapper.unwrapAny(e);
assertTrue(t instanceof Error);
assertEquals("msg", t.getMessage());
}
}
/**
* Generates a stack trace for a nested exception and checks the output
* for the nested exception.
*/
public void testStackTrace() {
/* Nested stack traces are not avilable in Java 1.3. */
String version = System.getProperty("java.version");
if (version.startsWith("1.3.")) {
return;
}
Exception ex = new Exception("some exception");
String causedBy = "Caused by: java.lang.Exception: some exception";
try {
throw new RuntimeExceptionWrapper(ex);
} catch (RuntimeException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String s = sw.toString();
assertTrue(s.indexOf(causedBy) != -1);
}
try {
throw new IOExceptionWrapper(ex);
} catch (IOException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
String s = sw.toString();
assertTrue(s.indexOf(causedBy) != -1);
}
}
}

View File

@@ -0,0 +1,72 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: FastOutputStreamTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.util.test;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.util.FastOutputStream;
import com.sleepycat.util.test.SharedTestUtils;
/**
* @author Mark Hayes
*/
public class FastOutputStreamTest extends TestCase {
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite(FastOutputStreamTest.class);
return suite;
}
public FastOutputStreamTest(String name) {
super(name);
}
public void setUp() {
SharedTestUtils.printTestName("FastOutputStreamTest." + getName());
}
public void testBufferSizing()
throws Exception {
FastOutputStream fos = new FastOutputStream();
assertEquals
(FastOutputStream.DEFAULT_INIT_SIZE, fos.getBufferBytes().length);
/* Write X+1 bytes, expect array size 2X+1 */
fos.write(new byte[FastOutputStream.DEFAULT_INIT_SIZE + 1]);
assertEquals
((FastOutputStream.DEFAULT_INIT_SIZE * 2) + 1,
fos.getBufferBytes().length);
/* Write X+1 bytes, expect array size 4X+3 = (2(2X+1) + 1) */
fos.write(new byte[FastOutputStream.DEFAULT_INIT_SIZE + 1]);
assertEquals
((FastOutputStream.DEFAULT_INIT_SIZE * 4) + 3,
fos.getBufferBytes().length);
}
}

View File

@@ -0,0 +1,191 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: PackedIntegerTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.util.test;
import com.sleepycat.util.PackedInteger;
import junit.framework.Test;
import junit.framework.TestCase;
public class PackedIntegerTest extends TestCase
{
static final long V119 = 119L;
static final long MAX_1 = 0xFFL;
static final long MAX_2 = 0xFFFFL;
static final long MAX_3 = 0xFFFFFFL;
static final long MAX_4 = 0xFFFFFFFFL;
static final long MAX_5 = 0xFFFFFFFFFFL;
static final long MAX_6 = 0xFFFFFFFFFFFFL;
static final long MAX_7 = 0xFFFFFFFFFFFFFFL;
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite() {
return new PackedIntegerTest();
}
public PackedIntegerTest() {
super("PackedIntegerTest");
}
public void runTest() {
/* Packed int tests. */
testIntRange(-V119, V119, 1);
testIntRange(-MAX_1 - V119, -1 - V119, 2);
testIntRange(1 + V119, MAX_1 + V119, 2);
testIntRange(-MAX_2 - V119, -MAX_2 + 99, 3);
testIntRange(-MAX_1 - V119 - 99, -MAX_1 - V119 - 1, 3);
testIntRange(MAX_1 + V119 + 1, MAX_1 + V119 + 99, 3);
testIntRange(MAX_2 - 99, MAX_2 + V119, 3);
testIntRange(-MAX_3 - V119, -MAX_3 + 99, 4);
testIntRange(-MAX_2 - V119 - 99, -MAX_2 - V119 - 1, 4);
testIntRange(MAX_2 + V119 + 1, MAX_2 + V119 + 99, 4);
testIntRange(MAX_3 - 99, MAX_3 + V119, 4);
testIntRange(Integer.MIN_VALUE, Integer.MIN_VALUE + 99, 5);
testIntRange(Integer.MAX_VALUE - 99, Integer.MAX_VALUE, 5);
/* Packed long tests. */
testLongRange(-V119, V119, 1);
testLongRange(-MAX_1 - V119, -1 - V119, 2);
testLongRange(1 + V119, MAX_1 + V119, 2);
testLongRange(-MAX_2 - V119, -MAX_2 + 99, 3);
testLongRange(-MAX_1 - V119 - 99, -MAX_1 - V119 - 1, 3);
testLongRange(MAX_1 + V119 + 1, MAX_1 + V119 + 99, 3);
testLongRange(MAX_2 - 99, MAX_2 + V119, 3);
testLongRange(-MAX_3 - V119, -MAX_3 + 99, 4);
testLongRange(-MAX_2 - V119 - 99, -MAX_2 - V119 - 1, 4);
testLongRange(MAX_2 + V119 + 1, MAX_2 + V119 + 99, 4);
testLongRange(MAX_3 - 99, MAX_3 + V119, 4);
testLongRange(-MAX_4 - V119, -MAX_4 + 99, 5);
testLongRange(-MAX_3 - V119 - 99, -MAX_3 - V119 - 1, 5);
testLongRange(MAX_3 + V119 + 1, MAX_3 + V119 + 99, 5);
testLongRange(MAX_4 - 99, MAX_4 + V119, 5);
testLongRange(-MAX_5 - V119, -MAX_5 + 99, 6);
testLongRange(-MAX_4 - V119 - 99, -MAX_4 - V119 - 1, 6);
testLongRange(MAX_4 + V119 + 1, MAX_4 + V119 + 99, 6);
testLongRange(MAX_5 - 99, MAX_5 + V119, 6);
testLongRange(-MAX_6 - V119, -MAX_6 + 99, 7);
testLongRange(-MAX_5 - V119 - 99, -MAX_5 - V119 - 1, 7);
testLongRange(MAX_5 + V119 + 1, MAX_5 + V119 + 99, 7);
testLongRange(MAX_6 - 99, MAX_6 + V119, 7);
testLongRange(-MAX_7 - V119, -MAX_7 + 99, 8);
testLongRange(-MAX_6 - V119 - 99, -MAX_6 - V119 - 1, 8);
testLongRange(MAX_6 + V119 + 1, MAX_6 + V119 + 99, 8);
testLongRange(MAX_7 - 99, MAX_7 + V119, 8);
testLongRange(Long.MIN_VALUE, Long.MIN_VALUE + 99, 9);
testLongRange(Long.MAX_VALUE - 99, Long.MAX_VALUE - 1, 9);
}
private void testIntRange(long firstValue,
long lastValue,
int bytesExpected) {
byte[] buf = new byte[1000];
int off = 0;
for (long longI = firstValue; longI <= lastValue; longI += 1) {
int i = (int) longI;
int before = off;
off = PackedInteger.writeInt(buf, off, i);
int bytes = off - before;
if (bytes != bytesExpected) {
fail("output of value=" + i + " bytes=" + bytes +
" bytesExpected=" + bytesExpected);
}
bytes = PackedInteger.getWriteIntLength(i);
if (bytes != bytesExpected) {
fail("count of value=" + i + " bytes=" + bytes +
" bytesExpected=" + bytesExpected);
}
}
off = 0;
for (long longI = firstValue; longI <= lastValue; longI += 1) {
int i = (int) longI;
int bytes = PackedInteger.getReadIntLength(buf, off);
if (bytes != bytesExpected) {
fail("count of value=" + i + " bytes=" + bytes +
" bytesExpected=" + bytesExpected);
}
int value = PackedInteger.readInt(buf, off);
if (value != i) {
fail("input of value=" + i + " but got=" + value);
}
off += bytes;
}
}
private void testLongRange(long firstValue,
long lastValue,
int bytesExpected) {
byte[] buf = new byte[2000];
int off = 0;
for (long longI = firstValue; longI <= lastValue; longI += 1) {
long i = longI;
int before = off;
off = PackedInteger.writeLong(buf, off, i);
int bytes = off - before;
if (bytes != bytesExpected) {
fail("output of value=" + i + " bytes=" + bytes +
" bytesExpected=" + bytesExpected);
}
bytes = PackedInteger.getWriteLongLength(i);
if (bytes != bytesExpected) {
fail("count of value=" + i + " bytes=" + bytes +
" bytesExpected=" + bytesExpected);
}
}
off = 0;
for (long longI = firstValue; longI <= lastValue; longI += 1) {
long i = longI;
int bytes = PackedInteger.getReadLongLength(buf, off);
if (bytes != bytesExpected) {
fail("count of value=" + i + " bytes=" + bytes +
" bytesExpected=" + bytesExpected);
}
long value = PackedInteger.readLong(buf, off);
if (value != i) {
fail("input of value=" + i + " but got=" + value);
}
off += bytes;
}
}
}

View File

@@ -0,0 +1,192 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: SharedTestUtils.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.util.test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import junit.framework.TestCase;
import com.sleepycat.db.DatabaseConfig;
/**
* Test utility methods shared by JE and DB core tests. Collections and
* persist package test are used in both JE and DB core.
*/
public class SharedTestUtils {
/* Common system properties for running tests */
public static String DEST_DIR = "testdestdir";
public static String NO_SYNC = "txnnosync";
public static String LONG_TEST = "longtest";
public static final DatabaseConfig DBCONFIG_CREATE = new DatabaseConfig();
static {
DBCONFIG_CREATE.setAllowCreate(true);
}
private static File getTestDir() {
String dir = System.getProperty(DEST_DIR);
if (dir == null || dir.length() == 0) {
throw new IllegalArgumentException
("System property must be set to test data directory: " +
DEST_DIR);
}
return new File(dir);
}
/**
* @return true if long running tests are enabled via setting the system
* property longtest=true.
*/
public static boolean runLongTests() {
String longTestProp = System.getProperty(LONG_TEST);
if ((longTestProp != null) &&
longTestProp.equalsIgnoreCase("true")) {
return true;
} else {
return false;
}
}
public static void printTestName(String name) {
// don't want verbose printing for now
// System.out.println(name);
}
public static File getExistingDir(String name)
throws IOException {
File dir = new File(getTestDir(), name);
if (!dir.exists() || !dir.isDirectory()) {
throw new IllegalStateException(
"Not an existing directory: " + dir);
}
return dir;
}
public static File getNewDir()
throws IOException {
return getNewDir("test-dir");
}
public static void emptyDir(File dir)
throws IOException {
if (dir.isDirectory()) {
String[] files = dir.list();
if (files != null) {
for (int i = 0; i < files.length; i += 1) {
new File(dir, files[i]).delete();
}
}
} else {
dir.delete();
dir.mkdirs();
}
}
public static File getNewDir(String name)
throws IOException {
File dir = new File(getTestDir(), name);
emptyDir(dir);
return dir;
}
public static File getNewFile()
throws IOException {
return getNewFile("test-file");
}
public static File getNewFile(String name)
throws IOException {
return getNewFile(getTestDir(), name);
}
public static File getNewFile(File dir, String name)
throws IOException {
File file = new File(dir, name);
file.delete();
return file;
}
public static boolean copyResource(Class cls, String fileName, File toDir)
throws IOException {
InputStream in = cls.getResourceAsStream("testdata/" + fileName);
if (in == null) {
return false;
}
in = new BufferedInputStream(in);
File file = new File(toDir, fileName);
OutputStream out = new FileOutputStream(file);
out = new BufferedOutputStream(out);
int c;
while ((c = in.read()) >= 0) out.write(c);
in.close();
out.close();
return true;
}
public static String qualifiedTestName(TestCase test) {
String s = test.getClass().getName();
int i = s.lastIndexOf('.');
if (i >= 0) {
s = s.substring(i + 1);
}
return s + '.' + test.getName();
}
/**
* Copies all files in fromDir to toDir. Does not copy subdirectories.
*/
public static void copyFiles(File fromDir, File toDir)
throws IOException {
String[] names = fromDir.list();
if (names != null) {
for (int i = 0; i < names.length; i += 1) {
File fromFile = new File(fromDir, names[i]);
if (fromFile.isDirectory()) {
continue;
}
File toFile = new File(toDir, names[i]);
int len = (int) fromFile.length();
byte[] data = new byte[len];
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(fromFile);
fos = new FileOutputStream(toFile);
fis.read(data);
fos.write(data);
} finally {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
}
}
}
}
}

View File

@@ -0,0 +1,144 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TestEnv.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.util.test;
import java.io.File;
import java.io.IOException;
import com.sleepycat.compat.DbCompat;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
/**
* @author Mark Hayes
*/
public class TestEnv {
public static final TestEnv BDB;
public static final TestEnv CDB;
public static final TestEnv TXN;
static {
EnvironmentConfig config;
config = newEnvConfig();
BDB = new TestEnv("bdb", config);
if (DbCompat.CDB) {
config = newEnvConfig();
DbCompat.setInitializeCDB(config, true);
CDB = new TestEnv("cdb", config);
} else {
CDB = null;
}
config = newEnvConfig();
config.setTransactional(true);
DbCompat.setInitializeLocking(config, true);
TXN = new TestEnv("txn", config);
}
private static EnvironmentConfig newEnvConfig() {
EnvironmentConfig config = new EnvironmentConfig();
config.setTxnNoSync(Boolean.getBoolean(SharedTestUtils.NO_SYNC));
if (DbCompat.MEMORY_SUBSYSTEM) {
DbCompat.setInitializeCache(config, true);
}
return config;
}
public static final TestEnv[] ALL;
static {
if (DbCompat.CDB) {
ALL = new TestEnv[] { BDB, CDB, TXN };
} else {
ALL = new TestEnv[] { BDB, TXN };
}
}
private String name;
private EnvironmentConfig config;
protected TestEnv(String name, EnvironmentConfig config) {
this.name = name;
this.config = config;
}
public String getName() {
return name;
}
public EnvironmentConfig getConfig() {
return config;
}
void copyConfig(EnvironmentConfig copyToConfig) {
DbCompat.setInitializeCache
(copyToConfig, DbCompat.getInitializeCache(config));
DbCompat.setInitializeLocking
(copyToConfig, DbCompat.getInitializeLocking(config));
DbCompat.setInitializeCDB
(copyToConfig, DbCompat.getInitializeCDB(config));
copyToConfig.setTransactional(config.getTransactional());
}
public boolean isTxnMode() {
return config.getTransactional();
}
public boolean isCdbMode() {
return DbCompat.getInitializeCDB(config);
}
public Environment open(String testName)
throws IOException, DatabaseException {
return open(testName, true);
}
public Environment open(String testName, boolean create)
throws IOException, DatabaseException {
config.setAllowCreate(create);
/* OLDEST deadlock detection on DB matches the use of timeouts on JE.*/
DbCompat.setLockDetectModeOldest(config);
File dir = getDirectory(testName, create);
return newEnvironment(dir, config);
}
/**
* Is overridden in XACollectionTest.
*/
protected Environment newEnvironment(File dir, EnvironmentConfig config)
throws DatabaseException, IOException {
return new Environment(dir, config);
}
public File getDirectory(String testName)
throws IOException {
return getDirectory(testName, true);
}
public File getDirectory(String testName, boolean create)
throws IOException {
if (create) {
return SharedTestUtils.getNewDir(testName);
} else {
return SharedTestUtils.getExistingDir(testName);
}
}
}

View File

@@ -0,0 +1,223 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: TxnTestCase.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.util.test;
import java.io.File;
import java.io.IOException;
import java.util.Enumeration;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;
import com.sleepycat.db.Transaction;
import com.sleepycat.db.TransactionConfig;
/**
* Permuates test cases over three transaction types: null (non-transactional),
* auto-commit, and user (explicit).
*
* <p>Overrides runTest, setUp and tearDown to open/close the environment and to
* set up protected members for use by test cases.</p>
*
* <p>If a subclass needs to override setUp or tearDown, the overridden method
* should call super.setUp or super.tearDown.</p>
*
* <p>When writing a test case based on this class, write it as if a user txn
* were always used: call txnBegin, txnCommit and txnAbort for all write
* operations. Use the isTransactional protected field for setup of a database
* config.</p>
*/
public abstract class TxnTestCase extends TestCase {
public static final String TXN_NULL = "txn-null";
public static final String TXN_AUTO = "txn-auto";
public static final String TXN_USER = "txn-user";
protected File envHome;
protected Environment env;
protected EnvironmentConfig envConfig;
protected String txnType;
protected boolean isTransactional;
/**
* Returns a txn test suite. If txnTypes is null, all three types are run.
*/
public static TestSuite txnTestSuite(Class testCaseClass,
EnvironmentConfig envConfig,
String[] txnTypes) {
if (txnTypes == null) {
txnTypes = new String[] { TxnTestCase.TXN_NULL,
TxnTestCase.TXN_USER,
TxnTestCase.TXN_AUTO };
}
if (envConfig == null) {
envConfig = new EnvironmentConfig();
envConfig.setAllowCreate(true);
}
TestSuite suite = new TestSuite();
for (int i = 0; i < txnTypes.length; i += 1) {
TestSuite baseSuite = new TestSuite(testCaseClass);
Enumeration e = baseSuite.tests();
while (e.hasMoreElements()) {
TxnTestCase test = (TxnTestCase) e.nextElement();
test.txnInit(envConfig, txnTypes[i]);
suite.addTest(test);
}
}
return suite;
}
private void txnInit(EnvironmentConfig envConfig, String txnType) {
this.envConfig = envConfig;
this.txnType = txnType;
isTransactional = (txnType != TXN_NULL);
}
public void setUp()
throws Exception {
envHome = SharedTestUtils.getNewDir();
}
public void runTest()
throws Throwable {
openEnv();
super.runTest();
closeEnv();
}
public void tearDown()
throws Exception {
/* Set test name for reporting; cannot be done in the ctor or setUp. */
setName(txnType + ':' + getName());
if (env != null) {
try {
env.close();
} catch (Throwable e) {
System.out.println("tearDown: " + e);
}
env = null;
}
try {
SharedTestUtils.emptyDir(envHome);
} catch (Throwable e) {
System.out.println("tearDown: " + e);
}
}
/**
* Closes the environment and sets the env field to null.
* Used for closing and reopening the environment.
*/
public void closeEnv()
throws DatabaseException {
if (env != null) {
env.close();
env = null;
}
}
/**
* Opens the environment based on the txnType for this test case.
* Used for closing and reopening the environment.
*/
public void openEnv()
throws IOException, DatabaseException {
if (txnType == TXN_NULL) {
TestEnv.BDB.copyConfig(envConfig);
env = new Environment(envHome, envConfig);
} else if (txnType == TXN_AUTO) {
TestEnv.TXN.copyConfig(envConfig);
env = new Environment(envHome, envConfig);
} else if (txnType == TXN_USER) {
TestEnv.TXN.copyConfig(envConfig);
env = new Environment(envHome, envConfig);
} else {
assert false;
}
}
/**
* Begin a txn if in TXN_USER mode; otherwise return null;
*/
protected Transaction txnBegin()
throws DatabaseException {
return txnBegin(null, null);
}
/**
* Begin a txn if in TXN_USER mode; otherwise return null;
*/
protected Transaction txnBegin(Transaction parentTxn,
TransactionConfig config)
throws DatabaseException {
if (txnType == TXN_USER) {
return env.beginTransaction(parentTxn, config);
} else {
return null;
}
}
/**
* Begin a txn if in TXN_USER or TXN_AUTO mode; otherwise return null;
*/
protected Transaction txnBeginCursor()
throws DatabaseException {
return txnBeginCursor(null, null);
}
/**
* Begin a txn if in TXN_USER or TXN_AUTO mode; otherwise return null;
*/
protected Transaction txnBeginCursor(Transaction parentTxn,
TransactionConfig config)
throws DatabaseException {
if (txnType == TXN_USER || txnType == TXN_AUTO) {
return env.beginTransaction(parentTxn, config);
} else {
return null;
}
}
/**
* Commit a txn if non-null.
*/
protected void txnCommit(Transaction txn)
throws DatabaseException {
if (txn != null) {
txn.commit();
}
}
/**
* Commit a txn if non-null.
*/
protected void txnAbort(Transaction txn)
throws DatabaseException {
if (txn != null) {
txn.abort();
}
}
}

View File

@@ -0,0 +1,168 @@
/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002,2008 Oracle. All rights reserved.
*
* $Id: UtfTest.java 63573 2008-05-23 21:43:21Z trent.nelson $
*/
package com.sleepycat.util.test;
import java.io.DataOutputStream;
import java.util.Arrays;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import com.sleepycat.util.FastOutputStream;
import com.sleepycat.util.UtfOps;
import com.sleepycat.util.test.SharedTestUtils;
/**
* @author Mark Hayes
*/
public class UtfTest extends TestCase {
public static void main(String[] args)
throws Exception {
junit.framework.TestResult tr =
junit.textui.TestRunner.run(suite());
if (tr.errorCount() > 0 ||
tr.failureCount() > 0) {
System.exit(1);
} else {
System.exit(0);
}
}
public static Test suite()
throws Exception {
TestSuite suite = new TestSuite(UtfTest.class);
return suite;
}
public UtfTest(String name) {
super(name);
}
public void setUp() {
SharedTestUtils.printTestName("UtfTest." + getName());
}
/**
* Compares the UtfOps implementation to the java.util.DataOutputStream
* (and by implication DataInputStream) implementation, character for
* character in the full Unicode set.
*/
public void testMultibyte()
throws Exception {
char c = 0;
byte[] buf = new byte[10];
byte[] javaBuf = new byte[10];
char[] cArray = new char[1];
FastOutputStream javaBufStream = new FastOutputStream(javaBuf);
DataOutputStream javaOutStream = new DataOutputStream(javaBufStream);
try {
for (int cInt = Character.MIN_VALUE; cInt <= Character.MAX_VALUE;
cInt += 1) {
c = (char) cInt;
cArray[0] = c;
int byteLen = UtfOps.getByteLength(cArray);
javaBufStream.reset();
javaOutStream.writeUTF(new String(cArray));
int javaByteLen = javaBufStream.size() - 2;
if (byteLen != javaByteLen) {
fail("Character 0x" + Integer.toHexString(c) +
" UtfOps size " + byteLen +
" != JavaIO size " + javaByteLen);
}
Arrays.fill(buf, (byte) 0);
UtfOps.charsToBytes(cArray, 0, buf, 0, 1);
if (byteLen == 1 && buf[0] == (byte) 0xff) {
fail("Character 0x" + Integer.toHexString(c) +
" was encoded as FF, which is reserved for null");
}
for (int i = 0; i < byteLen; i += 1) {
if (buf[i] != javaBuf[i + 2]) {
fail("Character 0x" + Integer.toHexString(c) +
" byte offset " + i +
" UtfOps byte " + Integer.toHexString(buf[i]) +
" != JavaIO byte " +
Integer.toHexString(javaBuf[i + 2]));
}
}
int charLen = UtfOps.getCharLength(buf, 0, byteLen);
if (charLen != 1) {
fail("Character 0x" + Integer.toHexString(c) +
" UtfOps char len " + charLen +
" but should be one");
}
cArray[0] = (char) 0;
int len = UtfOps.bytesToChars(buf, 0, cArray, 0, byteLen,
true);
if (len != byteLen) {
fail("Character 0x" + Integer.toHexString(c) +
" UtfOps bytesToChars(w/byteLen) len " + len +
" but should be " + byteLen);
}
if (cArray[0] != c) {
fail("Character 0x" + Integer.toHexString(c) +
" UtfOps bytesToChars(w/byteLen) char " +
Integer.toHexString(cArray[0]));
}
cArray[0] = (char) 0;
len = UtfOps.bytesToChars(buf, 0, cArray, 0, 1, false);
if (len != byteLen) {
fail("Character 0x" + Integer.toHexString(c) +
" UtfOps bytesToChars(w/charLen) len " + len +
" but should be " + byteLen);
}
if (cArray[0] != c) {
fail("Character 0x" + Integer.toHexString(c) +
" UtfOps bytesToChars(w/charLen) char " +
Integer.toHexString(cArray[0]));
}
String s = new String(cArray, 0, 1);
byte[] sBytes = UtfOps.stringToBytes(s);
if (sBytes.length != byteLen) {
fail("Character 0x" + Integer.toHexString(c) +
" UtfOps stringToBytes() len " + sBytes.length +
" but should be " + byteLen);
}
for (int i = 0; i < byteLen; i += 1) {
if (sBytes[i] != javaBuf[i + 2]) {
fail("Character 0x" + Integer.toHexString(c) +
" byte offset " + i +
" UtfOps byte " + Integer.toHexString(sBytes[i]) +
" != JavaIO byte " +
Integer.toHexString(javaBuf[i + 2]));
}
}
}
} catch (Exception e) {
System.out.println("Character 0x" + Integer.toHexString(c) +
" exception occurred");
throw e;
}
}
}