/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2000-2003
* Sleepycat Software. All rights reserved.
*
* $Id: ForeignKeyTest.java,v 1.10 2003/10/18 19:51:26 mhayes Exp $
*/
package com.sleepycat.bdb.test;
import com.sleepycat.bdb.bind.serial.test.MarshalledObject;
import com.sleepycat.db.Db;
import com.sleepycat.db.DbEnv;
import com.sleepycat.bdb.DataIndex;
import com.sleepycat.bdb.DataStore;
import com.sleepycat.bdb.ForeignKeyIndex;
import com.sleepycat.bdb.IntegrityConstraintException;
import com.sleepycat.bdb.StoredClassCatalog;
import com.sleepycat.bdb.TransactionRunner;
import com.sleepycat.bdb.TransactionWorker;
import com.sleepycat.bdb.factory.TupleSerialDbFactory;
import com.sleepycat.bdb.test.TestEnv;
import java.util.Map;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* @author Mark Hayes
*/
public class ForeignKeyTest extends TestCase
implements TransactionWorker {
private static final int[] ON_DELETE = {
ForeignKeyIndex.ON_DELETE_ABORT,
ForeignKeyIndex.ON_DELETE_CLEAR,
ForeignKeyIndex.ON_DELETE_CASCADE,
};
private static final String[] ON_DELETE_LABEL = {
"ON_DELETE_ABORT",
"ON_DELETE_CLEAR",
"ON_DELETE_CASCADE",
};
public static void main(String[] args)
throws Exception {
junit.textui.TestRunner.run(suite());
}
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 < ON_DELETE.length; j += 1) {
suite.addTest(new ForeignKeyTest(TestEnv.ALL[i],
ON_DELETE[j],
ON_DELETE_LABEL[j]));
}
}
return suite;
}
private TestEnv testEnv;
private DbEnv env;
private TransactionRunner runner;
private StoredClassCatalog catalog;
private TupleSerialDbFactory factory;
private DataStore store1;
private DataStore store2;
private DataIndex index1;
private ForeignKeyIndex index2;
private Map storeMap1;
private Map storeMap2;
private Map indexMap1;
private Map indexMap2;
private int onDelete;
private int openFlags;
public ForeignKeyTest(TestEnv testEnv, int onDelete,
String onDeleteLabel) {
super("ForeignKeyTest-" + testEnv.getName() + '-' + onDeleteLabel);
this.testEnv = testEnv;
this.onDelete = onDelete;
}
public void setUp()
throws Exception {
System.out.println(getName());
env = testEnv.open(getName());
openFlags = Db.DB_CREATE;
if (testEnv.isTxnMode())
openFlags |= Db.DB_AUTO_COMMIT;
runner = new TransactionRunner(env);
createDatabase();
}
public void tearDown() {
try {
if (store1 != null) {
store1.close();
store1 = null;
}
if (store2 != null) {
store2.close();
store2 = null;
}
if (catalog != null) {
catalog.close();
catalog = null;
}
if (env != null) {
env.close(0);
env = null;
}
} catch (Exception e) {
System.out.println("Ignored exception during tearDown: " + e);
}
}
public void runTest()
throws Exception {
runner.run(this);
}
public void doWork()
throws Exception {
createViews();
writeAndRead();
}
private void createDatabase()
throws Exception {
catalog = new StoredClassCatalog(env, "catalog.db", null, openFlags);
factory = new TupleSerialDbFactory(catalog);
assertSame(catalog, factory.getCatalog());
store1 = factory.newDataStore(openDb("store1.db"),
MarshalledObject.class, null);
index1 = factory.newDataIndex(store1, openDb("index1.db"),
"1", false, true);
store2 = factory.newDataStore(openDb("store2.db"),
MarshalledObject.class, null);
index2 = factory.newForeignKeyIndex(store2, openDb("index2.db"),
"2", false, true, store1, onDelete);
assertSame(index2.getForeignStore(), store1);
assertEquals(index2.getDeleteAction(), onDelete);
}
private Db openDb(String file)
throws Exception {
Db db = new Db(env, 0);
db.open(null, file, null, Db.DB_HASH, openFlags, 0);
return db;
}
private void createViews()
throws Exception {
storeMap1 = factory.newMap(store1, String.class, true);
storeMap2 = factory.newMap(store2, String.class, true);
indexMap1 = factory.newMap(index1, String.class, true);
indexMap2 = factory.newMap(index2, String.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
*/
switch (onDelete) {
case ForeignKeyIndex.ON_DELETE_ABORT:
try {
storeMap1.remove("pk1");
fail();
}
catch (IntegrityConstraintException expected) {}
o2 = new MarshalledObject("data2", "pk2", "", "");
assertNotNull(storeMap2.put(null, o2));
assertEquals(o2, storeMap2.get("pk2"));
assertNull(indexMap2.get("pk1"));
storeMap1.remove("pk1");
assertNull(storeMap1.get("pk1"));
assertNull(indexMap1.get("ik1"));
break;
case ForeignKeyIndex.ON_DELETE_CLEAR:
storeMap1.remove("pk1");
assertNull(storeMap1.get("pk1"));
assertNull(indexMap1.get("ik1"));
o2 = (MarshalledObject) storeMap2.get("pk2");
assertNotNull(o2);
assertEquals("data2", o2.getData());
assertEquals("pk2", o2.getPrimaryKey());
assertEquals("", o2.getIndexKey1());
assertEquals("", o2.getIndexKey2());
break;
case ForeignKeyIndex.ON_DELETE_CASCADE:
storeMap1.remove("pk1");
assertNull(storeMap1.get("pk1"));
assertNull(indexMap1.get("ik1"));
assertNull(storeMap2.get("pk2"));
assertNull(indexMap2.get("pk1"));
break;
default:
throw new IllegalStateException();
}
}
}