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 TestAssociate test application.
11 */
12
13package com.sleepycat.db.test;
14
15import org.junit.Before;
16import org.junit.After;
17import org.junit.AfterClass;
18import org.junit.BeforeClass;
19import org.junit.Test;
20import static org.junit.Assert.assertEquals;
21import static org.junit.Assert.fail;
22
23import java.io.File;
24import java.io.FileNotFoundException;
25import com.sleepycat.db.*;
26
27import com.sleepycat.db.DatabaseException;
28
29import com.sleepycat.db.test.TestUtils;
30
31public class AssociateTest {
32
33    public static final String ASSOCTEST_DBNAME  =       "associatetest.db";
34
35    public static final String[] DATABASETEST_SAMPLE_DATA =  {"abc", "def", "ghi", "JKL", "MNO", "pqrst", "UVW", "y", "Z"};
36
37    public static Database savedPriDb = null;
38    public static Database savedSecDb = null;
39
40    int callback_count = 0;
41    boolean callback_throws = false;
42
43    @BeforeClass public static void ClassInit() {
44	    TestUtils.loadConfig(null);
45        TestUtils.check_file_removed(TestUtils.getDBFileName(ASSOCTEST_DBNAME), true, true);
46	    TestUtils.removeall(true, true, TestUtils.BASETEST_DBDIR, TestUtils.getDBFileName(ASSOCTEST_DBNAME));
47    }
48
49    @AfterClass public static void ClassShutdown() {
50        TestUtils.removeall(true, true, TestUtils.BASETEST_DBDIR, TestUtils.getDBFileName(ASSOCTEST_DBNAME));
51    }
52
53    @Before public void PerTestInit()
54        throws Exception {
55    }
56
57    @After public void PerTestShutdown()
58        throws Exception {
59    }
60
61    /*
62     * Test creating a new database.
63     */
64    @Test public void test1()
65        throws DatabaseException, FileNotFoundException
66    {
67        int i;
68        EnvironmentConfig envc = new EnvironmentConfig();
69        envc.setAllowCreate(true);
70        envc.setInitializeCache(true);
71        Environment dbEnv = new Environment(TestUtils.BASETEST_DBFILE, envc);
72
73        DatabaseConfig dbConfig = new DatabaseConfig();
74        dbConfig.setErrorStream(TestUtils.getErrorStream());
75        dbConfig.setErrorPrefix("AssociateTest");
76        dbConfig.setType(DatabaseType.BTREE);
77        dbConfig.setAllowCreate(true);
78
79        Database priDb = dbEnv.openDatabase(null, ASSOCTEST_DBNAME, null, dbConfig);
80
81        SecondaryConfig secConfig = new SecondaryConfig();
82        secConfig.setAllowCreate(true);
83        secConfig.setType(DatabaseType.BTREE);
84        secConfig.setSortedDuplicates(true);
85        secConfig.setKeyCreator(new Capitalize());
86        SecondaryDatabase secDb = dbEnv.openSecondaryDatabase(null, ASSOCTEST_DBNAME+"2", null,
87                                                  priDb, secConfig);
88        savedPriDb = priDb;
89        savedSecDb = secDb;
90
91        // Insert records into the database
92        for(i =0; i < DATABASETEST_SAMPLE_DATA.length; i++)
93        {
94            String curdata = DATABASETEST_SAMPLE_DATA[i];
95            String reversed = (new StringBuffer(curdata)).reverse().toString();
96
97            DatabaseEntry key = new DatabaseEntry(curdata.getBytes());
98            key.setReuseBuffer(false);
99            DatabaseEntry data = new DatabaseEntry(reversed.getBytes());
100            data.setReuseBuffer(false);
101            try {
102                if (priDb.putNoOverwrite(null, key, data) == OperationStatus.KEYEXIST) {
103                    // should not in this - since we control the data.
104                    TestUtils.DEBUGOUT(2, "Key: " + curdata + " already exists\n");
105                }
106            } catch(DatabaseException dbe) {
107                TestUtils.ERR("Caught DatabaseException: " + dbe);
108            }
109        }
110
111        DatabaseEntry readkey = new DatabaseEntry();
112        readkey.setReuseBuffer(false);
113        DatabaseEntry readdata = new DatabaseEntry();
114        readdata.setReuseBuffer(false);
115        Cursor dbcp = priDb.openCursor(null, CursorConfig.DEFAULT);
116    	while (dbcp.getNext(readkey, readdata, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
117    	    String keystring = new String(readkey.getData());
118    	    String datastring = new String(readdata.getData());
119    	    String expecteddata = (new StringBuffer(keystring)).reverse().toString();
120
121    	    boolean found = false;
122            for(i = 0; i < DATABASETEST_SAMPLE_DATA.length; i++)
123            {
124                if(DATABASETEST_SAMPLE_DATA[i].compareTo(keystring) == 0)
125                    found = true;
126            }
127            if(!found)
128                TestUtils.ERR("Key: " + keystring + " retrieved from DB, but never added!");
129            if(datastring.compareTo(expecteddata) != 0)
130                TestUtils.ERR("Data: " + datastring + " does not match expected data: " + expecteddata);
131    	}
132
133        // Test secondary get functionality.
134        DatabaseEntry seckey = new DatabaseEntry();
135        seckey.setReuseBuffer(false);
136        DatabaseEntry secpkey = new DatabaseEntry();
137        secpkey.setReuseBuffer(false);
138        DatabaseEntry secdata = new DatabaseEntry();
139        secdata.setReuseBuffer(false);
140
141        seckey.setData("BC".getBytes());
142        if(secDb.get(null, seckey, secdata, null) == OperationStatus.SUCCESS)
143        {
144            TestUtils.DEBUGOUT(2, "seckey: " + new String(seckey.getData()) + " secdata: " +
145                new String(secdata.getData()));
146        } else {
147            TestUtils.ERR("Secondary get of key: " + new String(seckey.getData()) + " did not succeed.");
148        }
149        // pget
150        if(secDb.get(null, seckey, secpkey, secdata, null) == OperationStatus.SUCCESS)
151        {
152            TestUtils.DEBUGOUT(2, "seckey: " + new String(seckey.getData()) + " secdata: " +
153                new String(secdata.getData()) + " pkey: " + new String(secpkey.getData()));
154
155            // ensure that the retrievals are consistent using both primary and secondary keys.
156            DatabaseEntry tmpdata = new DatabaseEntry();
157            priDb.get(null, secpkey, tmpdata, null);
158            String tmpstr = new String(tmpdata.getData());
159            if(tmpstr.compareTo(new String(secdata.getData())) != 0)
160                TestUtils.ERR("Data retrieved from matching primary secondary keys is not consistent. secdata: " + new String(secdata.getData()) +
161                    " pridata: " + new String(tmpdata.getData()));
162        } else {
163            TestUtils.ERR("Secondary pget of key: " + new String(seckey.getData()) + " did not succeed.");
164        }
165        seckey.setData("KL".getBytes());
166        if(secDb.get(null, seckey, secdata, null) == OperationStatus.SUCCESS)
167        {
168            TestUtils.DEBUGOUT(2, "seckey: " + new String(seckey.getData()) + " secdata: " +
169                new String(secdata.getData()));
170        } else {
171            TestUtils.ERR("Secondary get of key: " + new String(seckey.getData()) + " did not succeed.");
172        }
173        // pget
174        if(secDb.get(null, seckey, secpkey, secdata, null) == OperationStatus.SUCCESS)
175        {
176            TestUtils.DEBUGOUT(2, "seckey: " + new String(seckey.getData()) + " secdata: " +
177                new String(secdata.getData()) + " pkey: " + new String(secpkey.getData()));
178
179            // ensure that the retrievals are consistent using both primary and secondary keys.
180            DatabaseEntry tmpdata = new DatabaseEntry();
181            priDb.get(null, secpkey, tmpdata, null);
182            String tmpstr = new String(tmpdata.getData());
183            if(tmpstr.compareTo(new String(secdata.getData())) != 0)
184                TestUtils.ERR("Data retrieved from matching primary secondary keys is not consistent. secdata: " + new String(secdata.getData()) +
185                    " pridata: " + new String(tmpdata.getData()));
186        } else {
187            TestUtils.ERR("Secondary pget of key: " + new String(seckey.getData()) + " did not succeed.");
188        }
189
190    }
191
192/**************************************************************************************
193 **************************************************************************************
194 **************************************************************************************/
195    /* creates a stupid secondary index as follows:
196     For an N letter key, we use N-1 letters starting at
197     position 1.  If the new letters are already capitalized,
198     we return the old array, but with offset set to 1.
199     If the letters are not capitalized, we create a new,
200     capitalized array.  This is pretty stupid for
201     an application, but it tests all the paths in the runtime.
202     */
203    public static class Capitalize implements SecondaryKeyCreator
204    {
205        public boolean createSecondaryKey(SecondaryDatabase secondary,
206                                      DatabaseEntry key,
207                                      DatabaseEntry data,
208                                      DatabaseEntry result)
209                throws DatabaseException
210        {
211            key.setReuseBuffer(false);
212            data.setReuseBuffer(false);
213            result.setReuseBuffer(false);
214            String which = "unknown db";
215            if (savedPriDb.equals(secondary)) {
216                which = "primary";
217            }
218            else if (savedSecDb.equals(secondary)) {
219                which = "secondary";
220            }
221    	    String keystring = new String(key.getData());
222    	    String datastring = new String(data.getData());
223            TestUtils.DEBUGOUT(2, "secondaryKeyCreate, Db: " + TestUtils.shownull(secondary) + "(" + which + "), key: " + keystring + ", data: " + datastring);
224            int len = key.getSize();
225            byte[] arr = key.getData();
226            boolean capped = true;
227
228            if (len < 1)
229                throw new DatabaseException("bad key");
230
231            result.setSize(len - 1);
232            for (int i=1; capped && i<len; i++) {
233                if (!Character.isUpperCase((char)arr[i]))
234                    capped = false;
235            }
236            if (capped) {
237                TestUtils.DEBUGOUT(2, "  creating key(1): " + new String(arr, 1, len-1));
238                result.setData(arr);
239                result.setOffset(1);
240                result.setSize(result.getSize() -1);
241            }
242            else {
243                TestUtils.DEBUGOUT(2, "  creating key(2): " + (new String(arr)).substring(1).
244                                   toUpperCase());
245                result.setData((new String(arr)).substring(1).
246                                toUpperCase().getBytes());
247            }
248            return true;
249        }
250    }
251
252}
253