/**
 * Copyright 2016 Palantir Technologies
 *
 * Licensed under the BSD-3 License (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://opensource.org/licenses/BSD-3-Clause
 *
 * 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 com.palantir.atlasdb.keyvalue.dbkvs;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.startsWith;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.sql.Connection;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import com.google.common.collect.ImmutableList;
import com.palantir.atlasdb.keyvalue.api.Namespace;
import com.palantir.atlasdb.keyvalue.api.TableReference;
import com.palantir.atlasdb.keyvalue.dbkvs.impl.ConnectionSupplier;
import com.palantir.atlasdb.keyvalue.impl.TableMappingNotFoundException;
import com.palantir.nexus.db.sql.AgnosticResultRow;
import com.palantir.nexus.db.sql.AgnosticResultSet;
import com.palantir.nexus.db.sql.SqlConnection;

public class OracleTableNameUnmapperTest {

    private static final String TEST_PREFIX = "a_";
    private static final Namespace TEST_NAMESPACE = Namespace.create("test_namespace");
    private static final String LONG_TABLE_NAME = "ThisIsAVeryLongTableNameThatWillExceed";
    private static final String SHORT_TABLE_NAME = "testShort";
    private static final TableReference TABLE_REF = TableReference.create(TEST_NAMESPACE, LONG_TABLE_NAME);

    private OracleTableNameUnmapper oracleTableNameUnmapper;
    private AgnosticResultSet resultSet;

    @Rule
    public ExpectedException expectedException = ExpectedException.none();

    @Before
    public void setup() {
        ConnectionSupplier connectionSupplier = mock(ConnectionSupplier.class);
        oracleTableNameUnmapper =  new OracleTableNameUnmapper(connectionSupplier);
        SqlConnection sqlConnection = mock(SqlConnection.class);
        Connection connection = mock(Connection.class);
        when(sqlConnection.getUnderlyingConnection()).thenReturn(connection);
        when(connectionSupplier.getFresh()).thenReturn(sqlConnection);

        resultSet = mock(AgnosticResultSet.class);
        when(sqlConnection
                .selectResultSetUnregisteredQuery(
                        startsWith("SELECT short_table_name FROM atlasdb_table_names WHERE table_name"), anyObject()))
                .thenReturn(resultSet);
    }

    @Test
    public void shouldThrowIfTableMappingDoesNotExist() throws TableMappingNotFoundException {
        when(resultSet.size()).thenReturn(0);

        expectedException.expect(TableMappingNotFoundException.class);
        expectedException.expectMessage("The table a_test_namespace__ThisIsAVeryLongTableNameThatWillExceed");
        oracleTableNameUnmapper.getShortTableNameFromMappingTable(TEST_PREFIX, TABLE_REF);
    }

    @Test
    public void shouldReturnIfTableMappingExists() throws TableMappingNotFoundException {
        when(resultSet.size()).thenReturn(1);

        AgnosticResultRow row = mock(AgnosticResultRow.class);
        when(row.getString(eq("short_table_name"))).thenReturn(SHORT_TABLE_NAME);
        doReturn(ImmutableList.of(row)).when(resultSet).rows();

        String shortName = oracleTableNameUnmapper.getShortTableNameFromMappingTable(TEST_PREFIX, TABLE_REF);
        assertThat(shortName, is(SHORT_TABLE_NAME));
    }
}

@@ -927,16 +927,99 @@
 o.mock;%0A
+import static org.mockito.Mockito.times;%0Aimport static org.mockito.Mockito.verify;%0A
 import s
@@ -1050,16 +1050,16 @@
 o.when;%0A
-
 %0Aimport 
@@ -1985,16 +1985,17 @@
 Short%22;%0A
+%0A
     priv
@@ -2094,16 +2094,133 @@
 _NAME);%0A
+    private static final TableReference TABLE_REF_2 = TableReference.create(TEST_NAMESPACE, LONG_TABLE_NAME + %222%22);%0A%0A
 %0A    pri
@@ -4064,24 +4064,24 @@
 TABLE_REF);%0A
-
         asse
@@ -4126,11 +4126,1002 @@
 );%0A    %7D
+%0A%0A    @Test%0A    public void cacheIsActuallyUsed() throws TableMappingNotFoundException %7B%0A        // do a normal read%0A        when(resultSet.size()).thenReturn(1);%0A%0A        AgnosticResultRow row = mock(AgnosticResultRow.class);%0A        when(row.getString(eq(%22short_table_name%22))).thenReturn(SHORT_TABLE_NAME);%0A        doReturn(ImmutableList.of(row)).when(resultSet).rows();%0A%0A        String shortName = oracleTableNameUnmapper.getShortTableNameFromMappingTable(TEST_PREFIX, TABLE_REF_2);%0A        assertThat(shortName, is(SHORT_TABLE_NAME));%0A%0A        // verify that underlying datastore was called once instead of hitting the cache%0A        verify(row, times(1)).getString(%22short_table_name%22);%0A%0A        // read again looking for the same table%0A        oracleTableNameUnmapper.getShortTableNameFromMappingTable(TEST_PREFIX, TABLE_REF_2);%0A%0A        // verify that cache was hit and underlying datastore was _still_ only called once%0A        verify(row, times(1)).getString(%22short_table_name%22);%0A    %7D
 %0A%7D%0A

add test for caching