1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2002,2008 Oracle.  All rights reserved.
5 *
6 */
7
8/*
9 * Alexg 23-4-06
10 * Based on scr016 TestConstruct01 and TestConstruct02
11 * test applications.
12 */
13
14package com.sleepycat.db.test;
15
16import org.junit.Before;
17import org.junit.After;
18import org.junit.AfterClass;
19import org.junit.BeforeClass;
20import org.junit.Test;
21import static org.junit.Assert.assertEquals;
22import static org.junit.Assert.fail;
23
24import com.sleepycat.db.Cursor;
25import com.sleepycat.db.CursorConfig;
26import com.sleepycat.db.Database;
27import com.sleepycat.db.DatabaseConfig;
28import com.sleepycat.db.DatabaseEntry;
29import com.sleepycat.db.DatabaseException;
30import com.sleepycat.db.DatabaseType;
31import com.sleepycat.db.Environment;
32import com.sleepycat.db.EnvironmentConfig;
33import com.sleepycat.db.LockMode;
34import com.sleepycat.db.OperationStatus;
35
36import java.io.File;
37import java.io.IOException;
38import java.io.FileNotFoundException;
39import com.sleepycat.db.test.TestUtils;
40
41public class DatabaseTest {
42
43    public static final String DATABASETEST_DBNAME  =       "databasetest.db";
44
45    private static int itemcount;	// count the number of items in the database
46
47    @BeforeClass public static void ClassInit() {
48	    TestUtils.loadConfig(null);
49        TestUtils.check_file_removed(TestUtils.getDBFileName(DATABASETEST_DBNAME), true, true);
50	    TestUtils.removeall(true, true, TestUtils.BASETEST_DBDIR, TestUtils.getDBFileName(DATABASETEST_DBNAME));
51        itemcount = 0;
52    }
53
54    @AfterClass public static void ClassShutdown() {
55        TestUtils.check_file_removed(TestUtils.getDBFileName(DATABASETEST_DBNAME), true, true);
56	    TestUtils.removeall(true, true, TestUtils.BASETEST_DBDIR, TestUtils.getDBFileName(DATABASETEST_DBNAME));
57    }
58
59    @Before public void PerTestInit()
60        throws Exception {
61    }
62
63    @After public void PerTestShutdown()
64        throws Exception {
65    }
66
67    /*
68     * Test creating a new database.
69     */
70    @Test public void test1()
71        throws DatabaseException, FileNotFoundException
72    {
73        TestOptions options = new TestOptions();
74        options.db_config.setErrorPrefix("DatabaseTest::test1 ");
75
76        rundb(itemcount++, options);
77    }
78
79    /*
80     * Test opening and adding to an existing database.
81     */
82    @Test public void test2()
83        throws DatabaseException, FileNotFoundException
84    {
85        TestOptions options = new TestOptions();
86        options.db_config.setErrorPrefix("DatabaseTest::test2 ");
87
88        rundb(itemcount++, options);
89    }
90
91    /*
92     * Test modifying the error prefix multiple times ?
93     */
94    @Test public void test3()
95        throws DatabaseException, FileNotFoundException
96    {
97        TestOptions options = new TestOptions();
98        options.db_config.setErrorPrefix("DatabaseTest::test3 ");
99
100        for (int i=0; i<100; i++)
101            options.db_config.setErrorPrefix("str" + i);
102
103        rundb(itemcount++, options);
104    }
105
106    /*
107     * Test opening a database with an env.
108     */
109    @Test public void test4()
110        throws DatabaseException, FileNotFoundException
111    {
112        TestOptions options = new TestOptions();
113        options.db_config.setErrorPrefix("DatabaseTest::test4 ");
114
115        EnvironmentConfig envc = new EnvironmentConfig();
116        envc.setAllowCreate(true);
117        envc.setInitializeCache(true);
118    	options.db_env = new Environment(TestUtils.BASETEST_DBFILE, envc);
119
120        rundb(itemcount++, options);
121        options.db_env.close();
122    }
123
124    /*
125     * Test opening multiple databases using the same env.
126     */
127    @Test public void test5()
128        throws DatabaseException, FileNotFoundException
129    {
130        TestOptions options = new TestOptions();
131        options.db_config.setErrorPrefix("DatabaseTest::test5 ");
132
133        EnvironmentConfig envc = new EnvironmentConfig();
134        envc.setAllowCreate(true);
135        envc.setInitializeCache(true);
136    	options.db_env = new Environment(TestUtils.BASETEST_DBFILE, envc);
137
138        rundb(itemcount++, options);
139
140        rundb(itemcount++, options);
141
142        options.db_env.close();
143    }
144
145    /*
146     * Test just opening and closing a DB and an Env without doing any operations.
147     */
148    @Test public void test6()
149        throws DatabaseException, FileNotFoundException
150    {
151        TestOptions options = new TestOptions();
152        options.db_config.setErrorPrefix("DatabaseTest::test6 ");
153
154        Database db = new Database(TestUtils.getDBFileName(DATABASETEST_DBNAME), null, options.db_config);
155
156        EnvironmentConfig envc = new EnvironmentConfig();
157        envc.setAllowCreate(true);
158        envc.setInitializeCache(true);
159    	Environment db_env = new Environment(TestUtils.BASETEST_DBFILE, envc);
160
161    	db.close();
162    	db_env.close();
163
164    	System.gc();
165    	System.runFinalization();
166    }
167
168    /*
169     * test7 leaves a db and dbenv open; it should be detected.
170     */
171    /* Not sure if relevant with current API.
172    @Test public void test7()
173        throws DatabaseException, FileNotFoundException
174    {
175        TestOptions options = new TestOptions();
176        options.db_config.setErrorPrefix("DatabaseTest::test7 ");
177
178        Database db = new Database(TestUtils.getDBFileName(DATABASETEST_DBNAME), null, options.db_config);
179
180        EnvironmentConfig envc = new EnvironmentConfig();
181        envc.setAllowCreate(true);
182        envc.setInitializeCache(true);
183    	Environment db_env = new Environment(TestUtils.BASETEST_DBFILE, envc);
184
185	    System.gc();
186	    System.runFinalization();
187    }
188    */
189
190    /*
191     * Test creating a new database.
192     */
193    @Test public void test8()
194        throws DatabaseException, FileNotFoundException
195    {
196	    TestUtils.removeall(true, false, TestUtils.BASETEST_DBDIR, TestUtils.getDBFileName(DATABASETEST_DBNAME));
197	    itemcount = 0;
198        TestOptions options = new TestOptions();
199        options.save_db = true;
200        options.db_config.setErrorPrefix("DatabaseTest::test8 ");
201
202        EnvironmentConfig envc = new EnvironmentConfig();
203        envc.setAllowCreate(true);
204        envc.setInitializeCache(true);
205    	options.db_env = new Environment(TestUtils.BASETEST_DBFILE, envc);
206
207        // stop rundb from closing the database, and pass in one created.
208    	rundb(itemcount++, options);
209    	rundb(itemcount++, options);
210    	rundb(itemcount++, options);
211    	rundb(itemcount++, options);
212    	rundb(itemcount++, options);
213    	rundb(itemcount++, options);
214
215    	options.database.close();
216    	options.database = null;
217
218    	// reopen the same database.
219    	rundb(itemcount++, options);
220    	rundb(itemcount++, options);
221    	rundb(itemcount++, options);
222    	rundb(itemcount++, options);
223    	rundb(itemcount++, options);
224    	rundb(itemcount++, options);
225
226        options.database.close();
227    	options.database = null;
228
229    }
230
231    // Check that key/data for 0 - count-1 are already present,
232    // and write a key/data for count.  The key and data are
233    // both "0123...N" where N == count-1.
234    //
235    // For some reason on Windows, we need to open using the full pathname
236    // of the file when there is no environment, thus the 'has_env'
237    // variable.
238    //
239    void rundb(int count, TestOptions options)
240            throws DatabaseException, FileNotFoundException
241    {
242    	String name;
243
244        Database db;
245        if(options.database == null)
246        {
247        	if (options.db_env != null)
248        	    name = DATABASETEST_DBNAME;
249        	else
250        	    name = TestUtils.getDBFileName(DATABASETEST_DBNAME);
251
252            if(count == 0)
253                options.db_config.setAllowCreate(true);
254
255            if(options.db_env == null)
256                db = new Database(name, null, options.db_config);
257            else
258                db = options.db_env.openDatabase(null, name, null, options.db_config);
259        } else {
260            db = options.database;
261        }
262
263    	// The bit map of keys we've seen
264    	long bitmap = 0;
265
266    	// The bit map of keys we expect to see
267    	long expected = (1 << (count+1)) - 1;
268
269    	byte outbuf[] = new byte[count+1];
270    	int i;
271    	for (i=0; i<count; i++) {
272    		outbuf[i] = (byte)('0' + i);
273    	}
274    	outbuf[i++] = (byte)'x';
275
276    	DatabaseEntry key = new DatabaseEntry(outbuf, 0, i);
277    	DatabaseEntry data = new DatabaseEntry(outbuf, 0, i);
278
279    	TestUtils.DEBUGOUT("Put: " + (char)outbuf[0] + ": " + new String(outbuf, 0, i));
280    	db.putNoOverwrite(null, key, data);
281
282    	// Acquire a cursor for the table.
283    	Cursor dbcp = db.openCursor(null, CursorConfig.DEFAULT);
284
285    	// Walk through the table, checking
286    	DatabaseEntry readkey = new DatabaseEntry();
287    	DatabaseEntry readdata = new DatabaseEntry();
288    	DatabaseEntry whoknows = new DatabaseEntry();
289
290    	/*
291    	 * NOTE: Maybe want to change from user-buffer to DB buffer
292    	 *       depending on the flag options.user_buffer (setReuseBuffer)
293    	 * The old version set MALLOC/REALLOC here - not sure if it is the same.
294    	 */
295
296    	TestUtils.DEBUGOUT("Dbc.get");
297    	while (dbcp.getNext(readkey, readdata, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
298    		String key_string =
299    		new String(readkey.getData(), 0, readkey.getSize());
300    		String data_string =
301    		new String(readdata.getData(), 0, readkey.getSize());
302    		TestUtils.DEBUGOUT("Got: " + key_string + ": " + data_string);
303    		int len = key_string.length();
304    		if (len <= 0 || key_string.charAt(len-1) != 'x') {
305    			TestUtils.ERR("reread terminator is bad");
306    		}
307    		len--;
308    		long bit = (1 << len);
309    		if (len > count) {
310    			TestUtils.ERR("reread length is bad: expect " + count + " got "+ len + " (" + key_string + ")" );
311    		}
312    		else if (!data_string.equals(key_string)) {
313    			TestUtils.ERR("key/data don't match");
314    		}
315    		else if ((bitmap & bit) != 0) {
316    			TestUtils.ERR("key already seen");
317    		}
318    		else if ((expected & bit) == 0) {
319    			TestUtils.ERR("key was not expected");
320    		}
321    		else {
322    			bitmap |= bit;
323    			expected &= ~(bit);
324    			for (i=0; i<len; i++) {
325    				if (key_string.charAt(i) != ('0' + i)) {
326    					System.out.print(" got " + key_string
327    					+ " (" + (int)key_string.charAt(i)
328    					+ "), wanted " + i
329    					+ " (" + (int)('0' + i)
330    					+ ") at position " + i + "\n");
331    					TestUtils.ERR("key is corrupt");
332    				}
333    			}
334    		}
335    	}
336    	if (expected != 0) {
337    		System.out.print(" expected more keys, bitmap is: " + expected + "\n");
338    		TestUtils.ERR("missing keys in database");
339    	}
340
341    	dbcp.close();
342    	TestUtils.DEBUGOUT("options.save_db " + options.save_db + " options.database " + options.database);
343    	if(options.save_db == false)
344    	    db.close(false);
345    	else if (options.database == null)
346    	    options.database = db;
347    }
348}
349
350
351class TestOptions
352{
353    int testmask = 0;           // which tests to run
354    int user_buffer = 0;    // use DB_DBT_USERMEM or DB_DBT_MALLOC
355    int successcounter =0;
356    boolean save_db = false;
357    Environment db_env = null;
358    DatabaseConfig db_config;
359    Database database = null; // db is saved here by rundb if save_db is true.
360
361    public TestOptions()
362    {
363        this.testmask = 0;
364        this.user_buffer = 0;
365        this.successcounter = 0;
366        this.db_env = null;
367
368        db_config = new DatabaseConfig();
369        db_config.setErrorStream(TestUtils.getErrorStream());
370        db_config.setErrorPrefix("DatabaseTest");
371        db_config.setType(DatabaseType.BTREE);
372    	// We don't really care about the pagesize
373        db_config.setPageSize(1024);
374
375    }
376
377}
378