lmdbjni-master/lmdbjni/src/test/java/org/fusesource/lmdbjni/test/LevelDBTest.java
/**
 * Copyright (C) 2013, RedHat, Inc.
 *
 *    http://www.redhat.com/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.fusesource.lmdbjni.test;

import junit.framework.TestCase;
import org.fusesource.lmdbjni.leveldb.LMDB;
import org.fusesource.lmdbjni.leveldb.LMDBFactory;
import org.fusesource.lmdbjni.leveldb.LMDBOptions;
import org.iq80.leveldb.*;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;

import static org.fusesource.lmdbjni.Constants.NOSYNC;
import static org.fusesource.lmdbjni.Constants.bytes;
import static org.fusesource.lmdbjni.Constants.string;

/**
 * A Unit test for the LevelDB API interface to LMDB.
 *
 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
 */
public class LevelDBTest extends TestCase {


    DBFactory factory = LMDBFactory.factory;

    static public void assertEquals(byte[] arg1, byte[] arg2) {
        assertTrue(Arrays.equals(arg1, arg2));
    }

    static File getTestDirectory(String name) throws IOException {
        File rc = new File(new File("test-data"), name);
        rc.mkdirs();
        return rc;
    }

    @Test
    public void testOpen() throws IOException {

        Options options = new Options().createIfMissing(true);

        File path = getTestDirectory(getName());
        DB db = factory.open(path, options);

        db.close();

        // Try again.. this time we expect a failure since it exists.
        options = new Options().errorIfExists(true);
        try {
            factory.open(path, options);
            fail("Expected exception.");
        } catch (IOException e) {
        }

    }

    @Test
    public void testCRUD() throws IOException, DBException {

        Options options = new Options().createIfMissing(true);

        File path = getTestDirectory(getName());
        DB db = factory.open(path, options);

        WriteOptions wo = new WriteOptions().sync(false);
        ReadOptions ro = new ReadOptions().fillCache(true).verifyChecksums(true);

        db.put(bytes("Tampa"), bytes("green"));
        db.put(bytes("London"), bytes("red"));
        db.put(bytes("New York"), bytes("blue"));

        assertEquals(db.get(bytes("Tampa"), ro), bytes("green"));
        assertEquals(db.get(bytes("London"), ro), bytes("red"));
        assertEquals(db.get(bytes("New York"), ro), bytes("blue"));

        db.delete(bytes("New York"), wo);
        assertNull(db.get(bytes("New York"), ro));

        // leveldb does not consider deleting something that does not exist an error.
        db.delete(bytes("New York"), wo);

        db.close();
    }

    @Test
    public void testIterator() throws IOException, DBException {

        Options options = new Options().createIfMissing(true);

        File path = getTestDirectory(getName());
        DB db = factory.open(path, options);

        db.put(bytes("a"), bytes("av"));
        db.put(bytes("c"), bytes("cv"));
        db.put(bytes("e"), bytes("ev"));

        ArrayList<String> expecting = new ArrayList<String>();
        expecting.add("av");
        expecting.add("cv");
        expecting.add("ev");

        ArrayList<String> actual = new ArrayList<String>();

        DBIterator iterator = db.iterator();
        for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) {
            actual.add(string(iterator.peekNext().getValue()));
        }
        iterator.close();

        assertEquals(expecting, actual);

        expecting = new ArrayList<String>();
        expecting.add("cv");
        expecting.add("ev");

        actual = new ArrayList<String>();

        iterator = db.iterator();
        for (iterator.seek(bytes("b")); iterator.hasNext(); iterator.next()) {
            actual.add(string(iterator.peekNext().getValue()));
        }
        iterator.close();

        iterator = db.iterator();
        for (iterator.seek(bytes("b")); iterator.hasPrev(); iterator.prev()) {
            actual.add(string(iterator.peekPrev().getValue()));
        }
        iterator.close();

        db.close();
    }

    @Test
    public void testSnapshot() throws IOException, DBException {

        Options options = new Options().createIfMissing(true);

        File path = getTestDirectory(getName());
        DB db = factory.open(path, options);

        db.put(bytes("Tampa"), bytes("green"));
        db.put(bytes("London"), bytes("red"));
        db.delete(bytes("New York"));

        ReadOptions ro = new ReadOptions().snapshot(db.getSnapshot());

        db.put(bytes("New York"), bytes("blue"));

        assertEquals(db.get(bytes("Tampa"), ro), bytes("green"));
        assertEquals(db.get(bytes("London"), ro), bytes("red"));

        // Should not be able to get "New York" since it was added
        // after the snapshot
        assertNull(db.get(bytes("New York"), ro));

        ro.snapshot().close();

        // Now try again without the snapshot..
        ro.snapshot(null);
        assertEquals(db.get(bytes("New York"), ro), bytes("blue"));

        db.close();
    }

    @Test
    public void testWriteBatch() throws IOException, DBException {

        Options options = new Options().createIfMissing(true);

        File path = getTestDirectory(getName());
        DB db = factory.open(path, options);

        db.put(bytes("NA"), bytes("Na"));

        WriteBatch batch = db.createWriteBatch();
        batch.delete(bytes("NA"));
        batch.put(bytes("Tampa"), bytes("green"));
        batch.put(bytes("London"), bytes("red"));
        batch.put(bytes("New York"), bytes("blue"));
        db.write(batch);
        batch.close();

        ArrayList<String> expecting = new ArrayList<String>();
        expecting.add("London");
        expecting.add("New York");
        expecting.add("Tampa");

        ArrayList<String> actual = new ArrayList<String>();

        DBIterator iterator = db.iterator();
        for (iterator.seekToFirst(); iterator.hasNext(); iterator.next()) {
            actual.add(string(iterator.peekNext().getKey()));
        }
        iterator.close();
        assertEquals(expecting, actual);

        db.close();
    }

    @Test
    public void testIssue26() throws IOException {

        LMDBFactory.pushMemoryPool(1024 * 512);
        try {
            LMDBOptions options = new LMDBOptions();
            options.createIfMissing(true);
            options.openFlags(NOSYNC); // this test would run too slow without this.

            LMDB db = (LMDB) factory.open(getTestDirectory(getName()), options);
            WriteOptions op = new WriteOptions();
            for (int i = 0; i < 1024 * 100; i++) {
                byte[] key = ByteBuffer.allocate(4).putInt(i).array();
                byte[] value = ByteBuffer.allocate(1024).putInt(-i).array();
                db.put(key, value, op);
                assertTrue(Arrays.equals(db.get(key), value));
            }
            System.out.println(db.getEnv().info());
            System.out.println(db.getEnv().stat());
            System.out.println(db.getDatabase().stat());
            db.close();
        } finally {
            LMDBFactory.popMemoryPool();
        }

    }

    @Test
    public void testIssue27() throws IOException {

        Options options = new Options();
        options.createIfMissing(true);
        DB db = factory.open(getTestDirectory(getName()), options);
        db.close();

        try {
            db.iterator();
            fail("Expected a DBException");
        } catch(DBException e) {
        }

    }

}
