/*
 * Copyright 2016-2018 shardingsphere.io.
 * <p>
 * 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.
 * </p>
 */

package io.shardingsphere.opentracing.listener.merger;

import io.opentracing.tag.Tags;
import io.shardingsphere.core.jdbc.core.ShardingContext;
import io.shardingsphere.core.jdbc.core.connection.ShardingConnection;
import io.shardingsphere.core.jdbc.core.statement.ShardingPreparedStatement;
import io.shardingsphere.core.jdbc.core.statement.ShardingStatement;
import io.shardingsphere.core.merger.MergeEngine;
import io.shardingsphere.core.merger.dal.DALMergeEngine;
import io.shardingsphere.core.parsing.parser.dialect.mysql.statement.ShowColumnsStatement;
import io.shardingsphere.core.parsing.parser.dialect.mysql.statement.ShowDatabasesStatement;
import io.shardingsphere.opentracing.fixture.ShardingContextBuilder;
import io.shardingsphere.opentracing.listener.BaseEventListenerTest;
import org.junit.Test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.SQLException;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

public final class MergeEventListenerTest extends BaseEventListenerTest {
    
    private final ShardingContext shardingContext;
    
    private final MergeEngine mergeEngine;
    
    public MergeEventListenerTest() throws SQLException {
        shardingContext = ShardingContextBuilder.build();
        mergeEngine = new DALMergeEngine(null, null, new ShowDatabasesStatement(), null);
    }
    
    @Test
    public void assertPreparedStatementRouting() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        ShardingPreparedStatement statement = new ShardingPreparedStatement(new ShardingConnection(shardingContext), "show databases");
        Method mergeMethod = ShardingPreparedStatement.class.getDeclaredMethod("merge", MergeEngine.class);
        mergeMethod.setAccessible(true);
        mergeMethod.invoke(statement, mergeEngine);
        assertThat(getTracer().finishedSpans().size(), is(1));
    }
    
    @Test
    public void assertStatementRouting() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        ShardingStatement statement = new ShardingStatement(new ShardingConnection(shardingContext));
        Method mergeMethod = ShardingStatement.class.getDeclaredMethod("merge", MergeEngine.class);
        mergeMethod.setAccessible(true);
        mergeMethod.invoke(statement, mergeEngine);
        assertThat(getTracer().finishedSpans().size(), is(1));
    }
    
    @Test
    public void assertException() {
        try {
            MergeEngine errorMergeEngine = new DALMergeEngine(null, null, new ShowColumnsStatement(), null);
            ShardingStatement statement = new ShardingStatement(new ShardingConnection(shardingContext));
            Method mergeMethod = ShardingStatement.class.getDeclaredMethod("merge", MergeEngine.class);
            mergeMethod.setAccessible(true);
            mergeMethod.invoke(statement, errorMergeEngine);
            // CHECKSTYLE:OFF
        } catch (final Exception ignored) {
            // CHECKSTYLE:ON
        }
        assertThat(getTracer().finishedSpans().size(), is(1));
        assertTrue((Boolean) getTracer().finishedSpans().get(0).tags().get(Tags.ERROR.getKey()));
    }
}

@@ -825,24 +825,95 @@
 Connection;%0A
+import io.shardingsphere.core.jdbc.core.datasource.ShardingDataSource;%0A
 import io.sh
@@ -969,32 +969,32 @@
 paredStatement;%0A
-
 import io.shardi
@@ -1497,16 +1497,44 @@
 it.Test;
+%0Aimport org.mockito.Mockito;
 %0A%0Aimport
@@ -1772,16 +1772,56 @@
 ertTrue;
+%0Aimport static org.mockito.Mockito.when;
 %0A%0Apublic
@@ -1993,24 +1993,86 @@
 ngine;%0A    %0A
+    private final ShardingDataSource shardingDataSource;%0A    %0A
     public M
@@ -2261,24 +2261,176 @@
 t(), null);%0A
+        shardingDataSource = Mockito.mock(ShardingDataSource.class);%0A        when(shardingDataSource.getShardingContext()).thenReturn(shardingContext);%0A
     %7D%0A    %0A 
@@ -2676,23 +2676,26 @@
 sharding
-Context
+DataSource
 ), %22show
@@ -3199,39 +3199,42 @@
 nection(sharding
-Context
+DataSource
 ));%0A        Meth
@@ -3752,23 +3752,26 @@
 sharding
-Context
+DataSource
 ));%0A    

use mock shardingDatasource