/*
 * The MIT License (MIT)
 * 
 * Copyright (c) 2013-2014 Jeff Nelson, Cinchapi Software Collective
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.cinchapi.concourse.server.storage.db;

import java.io.File;
import java.lang.reflect.Field;
import java.util.List;

import org.cinchapi.concourse.server.io.FileSystem;
import org.cinchapi.concourse.server.storage.Store;
import org.cinchapi.concourse.server.storage.StoreTest;
import org.cinchapi.concourse.server.storage.temp.Write;
import org.cinchapi.concourse.thrift.TObject;
import org.cinchapi.concourse.time.Time;
import org.cinchapi.concourse.util.TestData;
import org.junit.Assert;
import org.junit.Test;

/**
 * Unit tests for the {@link Database}.
 * 
 * @author jnelson
 */
public class DatabaseTest extends StoreTest {

    private String current;

    @Test
    public void testDatabaseRemovesUnbalancedBlocksOnStartup() throws Exception {
        Database db = (Database) store;
        db.accept(Write.add(TestData.getString(), TestData.getTObject(),
                TestData.getLong()));
        db.triggerSync();
        db.stop();
        FileSystem.deleteDirectory(current + File.separator + "csb");
        FileSystem.mkdirs(current + File.separator + "csb");
        db = new Database(db.getBackingStore()); // simulate server restart
        db.start();
        Field cpb = db.getClass().getDeclaredField("cpb");
        Field csb = db.getClass().getDeclaredField("csb");
        Field ctb = db.getClass().getDeclaredField("ctb");
        cpb.setAccessible(true);
        csb.setAccessible(true);
        ctb.setAccessible(true);
        Assert.assertEquals(1, ((List<?>) ctb.get(db)).size());
        Assert.assertEquals(1, ((List<?>) csb.get(db)).size());
        Assert.assertEquals(1, ((List<?>) cpb.get(db)).size());
    }

    @Override
    protected void add(String key, TObject value, long record) {
        if (!store.verify(key, value, record)) {
            ((Database) store).accept(Write.add(key, value, record));
        }
    }

    @Override
    protected void cleanup(Store store) {
        FileSystem.deleteDirectory(current);
    }

    @Override
    protected Database getStore() {
        current = TestData.DATA_DIR + File.separator + Time.now();
        return new Database(current);
    }

    @Override
    protected void remove(String key, TObject value, long record) {
        if (store.verify(key, value, record)) {
            ((Database) store).accept(Write.remove(key, value, record));
        }
    }

}

@@ -1521,16 +1521,63 @@
 .Write;%0A
+import org.cinchapi.concourse.thrift.Operator;%0A
 import o
@@ -1655,16 +1655,60 @@
 e.Time;%0A
+import org.cinchapi.concourse.util.Convert;%0A
 import o
@@ -2922,32 +2922,1322 @@
 size());%0A    %7D%0A%0A
+    @Test%0A    public void testDatabaseAppendsToCachedPartialPrimaryRecords() %7B%0A        Database db = (Database) store;%0A        String key = TestData.getString();%0A        long record = TestData.getLong();%0A        int count = TestData.getScaleCount();%0A        for (int i = 0; i %3C count; i++) %7B%0A            db.accept(Write.add(key, Convert.javaToThrift(i), record));%0A        %7D%0A        db.fetch(key, record);%0A        int increase = TestData.getScaleCount();%0A        db.accept(Write.add(key, Convert.javaToThrift(count * increase), record));%0A        Assert.assertTrue(db.fetch(key, record).contains(%0A                Convert.javaToThrift(count * increase)));%0A    %7D%0A%0A    @Test%0A    public void testDatabaseAppendsToCachedSecondaryRecords() %7B%0A        Database db = (Database) store;%0A        String key = TestData.getString();%0A        TObject value = TestData.getTObject();%0A        int count = TestData.getScaleCount();%0A        for (int i = 0; i %3C count; i++) %7B%0A            db.accept(Write.add(key, value, i));%0A        %7D%0A        db.find(key, Operator.EQUALS, value);%0A        int increase = TestData.getScaleCount();%0A        db.accept(Write.add(key, value, count * increase));%0A        Assert.assertTrue(db.find(key, Operator.EQUALS, value).contains(%0A                (long) count * increase)); %0A    %7D%0A%0A
     @Override%0A  
@@ -4309,17 +4309,16 @@
       if
- 
 (!store.
@@ -4796,17 +4796,16 @@
       if
- 
 (store.v

add unit tests to ensure that cached records in the database are updated