• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/db-4.7.25.NC/test/scr024/src/com/sleepycat/collections/test/
1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2000,2008 Oracle.  All rights reserved.
5 *
6 * $Id: ForeignKeyTest.java,v 12.1 2008/02/07 17:12:31 mark Exp $
7 */
8
9package com.sleepycat.collections.test;
10
11import java.util.Map;
12
13import junit.framework.Test;
14import junit.framework.TestCase;
15import junit.framework.TestSuite;
16
17import com.sleepycat.bind.serial.StoredClassCatalog;
18import com.sleepycat.bind.serial.TupleSerialMarshalledKeyCreator;
19import com.sleepycat.bind.serial.test.MarshalledObject;
20import com.sleepycat.collections.CurrentTransaction;
21import com.sleepycat.collections.TupleSerialFactory;
22import com.sleepycat.compat.DbCompat;
23import com.sleepycat.db.Database;
24import com.sleepycat.db.DatabaseConfig;
25import com.sleepycat.db.DatabaseException;
26import com.sleepycat.db.Environment;
27import com.sleepycat.db.ForeignKeyDeleteAction;
28import com.sleepycat.db.SecondaryConfig;
29import com.sleepycat.db.SecondaryDatabase;
30import com.sleepycat.util.ExceptionUnwrapper;
31import com.sleepycat.util.RuntimeExceptionWrapper;
32import com.sleepycat.util.test.SharedTestUtils;
33import com.sleepycat.util.test.TestEnv;
34
35/**
36 * @author Mark Hayes
37 */
38public class ForeignKeyTest extends TestCase {
39
40    private static final ForeignKeyDeleteAction[] ACTIONS = {
41        ForeignKeyDeleteAction.ABORT,
42        ForeignKeyDeleteAction.NULLIFY,
43        ForeignKeyDeleteAction.CASCADE,
44    };
45    private static final String[] ACTION_LABELS = {
46        "ABORT",
47        "NULLIFY",
48        "CASCADE",
49    };
50
51    public static void main(String[] args)
52        throws Exception {
53
54        junit.framework.TestResult tr =
55            junit.textui.TestRunner.run(suite());
56        if (tr.errorCount() > 0 ||
57            tr.failureCount() > 0) {
58            System.exit(1);
59        } else {
60            System.exit(0);
61        }
62    }
63
64    public static Test suite()
65        throws Exception {
66
67        TestSuite suite = new TestSuite();
68        for (int i = 0; i < TestEnv.ALL.length; i += 1) {
69            for (int j = 0; j < ACTIONS.length; j += 1) {
70                suite.addTest(new ForeignKeyTest(TestEnv.ALL[i],
71                                                 ACTIONS[j],
72                                                 ACTION_LABELS[j]));
73            }
74        }
75        return suite;
76    }
77
78    private TestEnv testEnv;
79    private Environment env;
80    private StoredClassCatalog catalog;
81    private TupleSerialFactory factory;
82    private Database store1;
83    private Database store2;
84    private SecondaryDatabase index1;
85    private SecondaryDatabase index2;
86    private Map storeMap1;
87    private Map storeMap2;
88    private Map indexMap1;
89    private Map indexMap2;
90    private ForeignKeyDeleteAction onDelete;
91
92    public ForeignKeyTest(TestEnv testEnv, ForeignKeyDeleteAction onDelete,
93                          String onDeleteLabel) {
94
95        super("ForeignKeyTest-" + testEnv.getName() + '-' + onDeleteLabel);
96
97        this.testEnv = testEnv;
98        this.onDelete = onDelete;
99    }
100
101    public void setUp()
102        throws Exception {
103
104        SharedTestUtils.printTestName(getName());
105        env = testEnv.open(getName());
106
107        createDatabase();
108    }
109
110    public void tearDown() {
111
112        try {
113            if (index1 != null) {
114                index1.close();
115            }
116            if (index2 != null) {
117                index2.close();
118            }
119            if (store1 != null) {
120                store1.close();
121            }
122            if (store2 != null) {
123                store2.close();
124            }
125            if (catalog != null) {
126                catalog.close();
127            }
128            if (env != null) {
129                env.close();
130            }
131        } catch (Exception e) {
132            System.out.println("Ignored exception during tearDown: " + e);
133	} finally {
134            /* Ensure that GC can cleanup. */
135            env = null;
136	    testEnv = null;
137            catalog = null;
138            store1 = null;
139            store2 = null;
140            index1 = null;
141            index2 = null;
142            factory = null;
143            storeMap1 = null;
144            storeMap2 = null;
145            indexMap1 = null;
146            indexMap2 = null;
147        }
148    }
149
150    public void runTest()
151        throws Exception {
152
153        try {
154            createViews();
155            writeAndRead();
156        } catch (Exception e) {
157            throw ExceptionUnwrapper.unwrap(e);
158        }
159    }
160
161    private void createDatabase()
162        throws Exception {
163
164        catalog = new StoredClassCatalog(openDb("catalog.db"));
165        factory = new TupleSerialFactory(catalog);
166        assertSame(catalog, factory.getCatalog());
167
168        store1 = openDb("store1.db");
169        store2 = openDb("store2.db");
170        index1 = openSecondaryDb(factory, "1", store1, "index1.db", null);
171        index2 = openSecondaryDb(factory, "2", store2, "index2.db", store1);
172    }
173
174    private Database openDb(String file)
175        throws Exception {
176
177        DatabaseConfig config = new DatabaseConfig();
178        DbCompat.setTypeBtree(config);
179        config.setTransactional(testEnv.isTxnMode());
180        config.setAllowCreate(true);
181
182        return DbCompat.testOpenDatabase(env, null, file, null, config);
183    }
184
185    private SecondaryDatabase openSecondaryDb(TupleSerialFactory factory,
186                                              String keyName,
187                                              Database primary,
188                                              String file,
189                                              Database foreignStore)
190        throws Exception {
191
192        TupleSerialMarshalledKeyCreator keyCreator =
193                factory.getKeyCreator(MarshalledObject.class, keyName);
194
195        SecondaryConfig secConfig = new SecondaryConfig();
196        DbCompat.setTypeBtree(secConfig);
197        secConfig.setTransactional(testEnv.isTxnMode());
198        secConfig.setAllowCreate(true);
199        secConfig.setKeyCreator(keyCreator);
200        if (foreignStore != null) {
201            secConfig.setForeignKeyDatabase(foreignStore);
202            secConfig.setForeignKeyDeleteAction(onDelete);
203            if (onDelete == ForeignKeyDeleteAction.NULLIFY) {
204                secConfig.setForeignKeyNullifier(keyCreator);
205            }
206        }
207
208        return DbCompat.testOpenSecondaryDatabase
209            (env, null, file, null, primary, secConfig);
210    }
211
212    private void createViews()
213        throws Exception {
214
215        storeMap1 = factory.newMap(store1, String.class,
216                                   MarshalledObject.class, true);
217        storeMap2 = factory.newMap(store2, String.class,
218                                   MarshalledObject.class, true);
219        indexMap1 = factory.newMap(index1, String.class,
220                                   MarshalledObject.class, true);
221        indexMap2 = factory.newMap(index2, String.class,
222                                   MarshalledObject.class, true);
223    }
224
225    private void writeAndRead()
226        throws Exception {
227
228        CurrentTransaction txn = CurrentTransaction.getInstance(env);
229        if (txn != null) {
230            txn.beginTransaction(null);
231        }
232
233        MarshalledObject o1 = new MarshalledObject("data1", "pk1", "ik1", "");
234        assertNull(storeMap1.put(null, o1));
235
236        assertEquals(o1, storeMap1.get("pk1"));
237        assertEquals(o1, indexMap1.get("ik1"));
238
239        MarshalledObject o2 = new MarshalledObject("data2", "pk2", "", "pk1");
240        assertNull(storeMap2.put(null, o2));
241
242        assertEquals(o2, storeMap2.get("pk2"));
243        assertEquals(o2, indexMap2.get("pk1"));
244
245        if (txn != null) {
246            txn.commitTransaction();
247            txn.beginTransaction(null);
248        }
249
250        /*
251         * store1 contains o1 with primary key "pk1" and index key "ik1".
252         *
253         * store2 contains o2 with primary key "pk2" and foreign key "pk1",
254         * which is the primary key of store1.
255         */
256
257        if (onDelete == ForeignKeyDeleteAction.ABORT) {
258
259            /* Test that we abort trying to delete a referenced key. */
260
261            try {
262                storeMap1.remove("pk1");
263                fail();
264            } catch (RuntimeExceptionWrapper expected) {
265                assertTrue(expected.getCause() instanceof DatabaseException);
266                if (txn != null) {
267                    txn.abortTransaction();
268                    txn.beginTransaction(null);
269                }
270            }
271
272            /* Test that we can put a record into store2 with a null foreign
273             * key value. */
274
275            o2 = new MarshalledObject("data2", "pk2", "", "");
276            assertNotNull(storeMap2.put(null, o2));
277            assertEquals(o2, storeMap2.get("pk2"));
278
279            /* The index2 record should have been deleted since the key was set
280             * to null above. */
281
282            assertNull(indexMap2.get("pk1"));
283
284            /* Test that now we can delete the record in store1, since it is no
285             * longer referenced. */
286
287            assertNotNull(storeMap1.remove("pk1"));
288            assertNull(storeMap1.get("pk1"));
289            assertNull(indexMap1.get("ik1"));
290
291        } else if (onDelete == ForeignKeyDeleteAction.NULLIFY) {
292
293            /* Delete the referenced key. */
294
295            assertNotNull(storeMap1.remove("pk1"));
296            assertNull(storeMap1.get("pk1"));
297            assertNull(indexMap1.get("ik1"));
298
299            /* The store2 record should still exist, but should have an empty
300             * secondary key since it was nullified. */
301
302            o2 = (MarshalledObject) storeMap2.get("pk2");
303            assertNotNull(o2);
304            assertEquals("data2", o2.getData());
305            assertEquals("pk2", o2.getPrimaryKey());
306            assertEquals("", o2.getIndexKey1());
307            assertEquals("", o2.getIndexKey2());
308
309        } else if (onDelete == ForeignKeyDeleteAction.CASCADE) {
310
311            /* Delete the referenced key. */
312
313            assertNotNull(storeMap1.remove("pk1"));
314            assertNull(storeMap1.get("pk1"));
315            assertNull(indexMap1.get("ik1"));
316
317            /* The store2 record should have deleted also. */
318
319            assertNull(storeMap2.get("pk2"));
320            assertNull(indexMap2.get("pk1"));
321
322        } else {
323            throw new IllegalStateException();
324        }
325
326        /*
327         * Test that a foreign key value may not be used that is not present
328         * in the foreign store. "pk2" is not in store1 in this case.
329         */
330        assertNull(storeMap1.get("pk2"));
331        MarshalledObject o3 = new MarshalledObject("data3", "pk3", "", "pk2");
332        try {
333            storeMap2.put(null, o3);
334            fail();
335        } catch (RuntimeExceptionWrapper expected) {
336            assertTrue(expected.getCause() instanceof DatabaseException);
337        }
338
339        if (txn != null) {
340            txn.commitTransaction();
341        }
342    }
343}
344