001: /*
002: * $Id: AbstractIndexTest.java,v 1.5 2005/12/20 18:32:44 ahimanikya Exp $
003: * =======================================================================
004: * Copyright (c) 2002 Axion Development Team. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above
011: * copyright notice, this list of conditions and the following
012: * disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The names "Tigris", "Axion", nor the names of its contributors may
020: * not be used to endorse or promote products derived from this
021: * software without specific prior written permission.
022: *
023: * 4. Products derived from this software may not be called "Axion", nor
024: * may "Tigris" or "Axion" appear in their names without specific prior
025: * written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
028: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
029: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
030: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
031: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
032: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
033: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
034: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
035: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
036: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
037: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
038: * =======================================================================
039: */
040:
041: package org.axiondb;
042:
043: import java.io.File;
044: import java.util.ArrayList;
045: import java.util.HashSet;
046: import java.util.Iterator;
047: import java.util.List;
048: import java.util.Set;
049:
050: import org.apache.commons.logging.Log;
051: import org.apache.commons.logging.LogFactory;
052: import org.axiondb.engine.rows.SimpleRow;
053: import org.axiondb.engine.tables.MemoryTable;
054: import org.axiondb.functions.EqualFunction;
055: import org.axiondb.types.IntegerType;
056:
057: /**
058: * Utility test environment for various types of indices
059: *
060: * @version $Revision: 1.5 $ $Date: 2005/12/20 18:32:44 $
061: * @author Chuck Burdick
062: */
063: public abstract class AbstractIndexTest extends AbstractDbdirTest {
064: private Log _log = LogFactory.getLog(this .getClass());
065: private Table _table = null;
066: private Column _col = null;
067: private Index _index = null;
068: private int _testCount = 50;
069:
070: public AbstractIndexTest(String testName) {
071: super (testName);
072: }
073:
074: public void setUp() throws Exception {
075: super .setUp();
076: _table = new MemoryTable("FOO");
077: _table.addColumn(new Column("ID", new IntegerType()));
078: _col = new Column("BAR", getDataType());
079: _table.addColumn(_col);
080: _index = createIndex("BAR", _col, false);
081: _table.addIndex(_index);
082: }
083:
084: public void tearDown() throws Exception {
085: _index = null;
086: super .tearDown();
087: }
088:
089: //============================================================= TEST CASES
090:
091: public void testHelpers() throws Exception {
092: assertEquals(
093: "Objects of same sequential index should report equality",
094: getSequentialValue(101), getSequentialValue(101));
095: }
096:
097: public void testBasics() throws Exception {
098: assertNotNull("Should have a table", getTable());
099: assertNotNull("Should have a column", getColumn());
100: assertNotNull("Should have an index", getIndex());
101: assertEquals("Index should report its name", "BAR", getIndex()
102: .getName());
103: assertEquals("Table should report the index on the column",
104: getTable().getIndexForColumn(getColumn()), getIndex());
105: assertEquals("Index should report the indexed column",
106: getColumn(), getIndex().getIndexedColumn());
107: }
108:
109: public void testChangeRowId() throws Exception {
110: // This test assumes I can call getRowIterator,
111: // RowIterator.next and Row.getIdentifier
112: // with an identifier that doesn't
113: // actually exist in the table.
114: // This assumption may not always be valid, at which
115: // point this test may need to be reconsidered.
116:
117: Row row = new SimpleRow(2);
118: row.set(0, new Integer(1));
119: row.set(1, getSequentialValue(1));
120: getTable().addRow(row);
121:
122: {
123: RowIterator iter = getIndex().getRowIterator(getTable(),
124: new EqualFunction(), getSequentialValue(1));
125: Row result = iter.next();
126: assertEquals(row.getIdentifier(), result.getIdentifier());
127: }
128:
129: getIndex().changeRowId(getTable(), row, row.getIdentifier(),
130: row.getIdentifier() + 1000);
131:
132: {
133: RowIterator iter = getIndex().getRowIterator(getTable(),
134: new EqualFunction(), getSequentialValue(1));
135: Row result = iter.next();
136: assertEquals(row.getIdentifier() + 1000, result
137: .getIdentifier());
138: }
139:
140: }
141:
142: public void testSequentialAdds() throws Exception {
143: List tests = new ArrayList();
144: for (int i = 0; i < _testCount; i++) {
145: Row row = new SimpleRow(2);
146: row.set(0, new Integer(i));
147: Object cur = getSequentialValue(i);
148: _log.debug("Inserting value " + cur);
149: tests.add(cur);
150: row.set(1, cur);
151: getTable().addRow(row);
152: }
153:
154: for (int i = 0; i < _testCount; i++) {
155: RowIterator it = getIndex().getRowIterator(getTable(),
156: new EqualFunction(), getSequentialValue(i));
157: assertTrue("Should have row for item " + i, it.hasNext());
158: Row cur = it.next();
159: assertEquals("Returned row id should match",
160: new Integer(i), cur.get(0));
161: assertEquals("Returned object should match", tests.get(i),
162: cur.get(1));
163: }
164: }
165:
166: public void testRandomAdds() throws Exception {
167: Set tests = new HashSet();
168: Object cur = null;
169: for (int i = 0; i < _testCount; i++) {
170: cur = getRandomValue();
171: if (tests.contains(cur)) {
172: i--;
173: } else {
174: Row row = new SimpleRow(2);
175: row.set(0, new Integer(i));
176: tests.add(cur);
177: row.set(1, cur);
178: getTable().addRow(row);
179: }
180: }
181:
182: Iterator testIt = tests.iterator();
183: while (testIt.hasNext()) {
184: cur = testIt.next();
185: RowIterator it = getIndex().getRowIterator(getTable(),
186: new EqualFunction(), cur);
187: assertTrue("Should have row for item " + cur, it.hasNext());
188: Row curRow = it.next();
189: assertEquals("Returned object should match", cur, curRow
190: .get(1));
191: }
192: }
193:
194: public void testDeletes() throws Exception {
195: testRandomAdds();
196: RowIterator rIt = getTable().getRowIterator(false);
197: while (rIt.hasNext()) {
198: Row curRow = rIt.next();
199: Object curVal = curRow.get(1);
200: RowIterator it = getIndex().getRowIterator(getTable(),
201: new EqualFunction(), curVal);
202: assertTrue("Index should find value", it.hasNext());
203: rIt.remove();
204: it = getIndex().getRowIterator(getTable(),
205: new EqualFunction(), curVal);
206: assertTrue("Index should not find value", !it.hasNext());
207: }
208: }
209:
210: public void testSaveAndLoad() throws Exception {
211: testRandomAdds();
212:
213: File idxDir = new File(getDbdir(), "BAR");
214: idxDir.mkdir();
215:
216: getIndex().getIndexLoader().saveIndex(getIndex(), idxDir);
217:
218: getTable().removeIndex(getIndex());
219:
220: Index loadedIndex = getIndex().getIndexLoader().loadIndex(
221: getTable(), idxDir);
222:
223: getTable().addIndex(loadedIndex);
224:
225: assertEquals("Index should report its name", "BAR", loadedIndex
226: .getName());
227:
228: assertEquals("Table should report the index on the column",
229: loadedIndex, getTable().getIndexForColumn(getColumn()));
230:
231: assertEquals("Index should report the indexed column",
232: getColumn(), loadedIndex.getIndexedColumn());
233:
234: RowIterator rIt = getTable().getRowIterator(true);
235: while (rIt.hasNext()) {
236: Row curRow = rIt.next();
237: Object curVal = curRow.get(1);
238: RowIterator it = loadedIndex.getRowIterator(getTable(),
239: new EqualFunction(), curVal);
240: assertTrue("Index should find value", it.hasNext());
241: }
242:
243: deleteFile(idxDir);
244: }
245:
246: /**
247: * Checks for dealing with NULL properly, was throwing an NPE for BTREE indexes
248: */
249: public void testNull() throws Exception {
250: Row row = new SimpleRow(2);
251: row.set(0, null);
252: getTable().addRow(row);
253: RowIterator rIt = getIndex().getRowIterator(getTable(),
254: new EqualFunction(), null);
255: assertTrue("Should get empty row iterator back", rIt.isEmpty());
256: rIt = getTable().getRowIterator(false);
257: while (rIt.hasNext()) {
258: rIt.next();
259: rIt.remove();
260: }
261: }
262:
263: //========================================================= TEST FRAMEWORK
264:
265: /**
266: * Subclasses implement so that framework can perform tests on the target index type
267: */
268: protected abstract Index createIndex(String name, Column col,
269: boolean unique) throws AxionException;
270:
271: /**
272: * Subclasses implement to inform test table what type of column should be indexed
273: */
274: protected abstract DataType getDataType();
275:
276: /**
277: * Subclasses implement to provide a unique value appropriate for the type in {$link
278: * getDataType} for each value <code>i</code>.
279: */
280: protected abstract Object getSequentialValue(int i);
281:
282: /**
283: * Subclasses implement to provide a random value appropriate for the type in {$link
284: * getDataType}.
285: */
286: protected abstract Object getRandomValue();
287:
288: //=============================================== ACCESSORS FOR SUBCLASSES
289:
290: /**
291: * Test table with two columns. One column is a numeric ID, the other is of the type
292: * provided in {@link #getDataType}
293: */
294: protected Table getTable() {
295: return _table;
296: }
297:
298: /**
299: * Column of type provided in {@link #getDataType}
300: */
301: protected Column getColumn() {
302: return _col;
303: }
304:
305: /**
306: * Target index to be tested
307: *
308: * @see #getIndexFactory
309: * @see #getIndexLoader
310: */
311: protected Index getIndex() {
312: return _index;
313: }
314: }
|