/*
 * 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.shardingproxy.transport.mysql.packet.command.query.text.fieldlist;

import com.google.common.base.Optional;
import io.shardingsphere.core.constant.ShardingConstant;
import io.shardingsphere.shardingproxy.backend.BackendHandler;
import io.shardingsphere.shardingproxy.backend.ResultPacket;
import io.shardingsphere.shardingproxy.backend.jdbc.connection.BackendConnection;
import io.shardingsphere.shardingproxy.transport.common.packet.DatabasePacket;
import io.shardingsphere.shardingproxy.transport.mysql.constant.ColumnType;
import io.shardingsphere.shardingproxy.transport.mysql.constant.ServerErrorCode;
import io.shardingsphere.shardingproxy.transport.mysql.packet.MySQLPacketPayload;
import io.shardingsphere.shardingproxy.transport.mysql.packet.command.CommandPacketType;
import io.shardingsphere.shardingproxy.transport.mysql.packet.command.CommandResponsePackets;
import io.shardingsphere.shardingproxy.transport.mysql.packet.command.query.ColumnDefinition41Packet;
import io.shardingsphere.shardingproxy.transport.mysql.packet.command.query.FieldCountPacket;
import io.shardingsphere.shardingproxy.transport.mysql.packet.generic.EofPacket;
import io.shardingsphere.shardingproxy.transport.mysql.packet.generic.ErrPacket;
import lombok.SneakyThrows;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Iterator;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public final class ComFieldListPacketTest {
    
    @Mock
    private MySQLPacketPayload payload;
    
    @Mock
    private BackendConnection backendConnection;
    
    @Mock
    private BackendHandler backendHandler;
    
    @Test
    public void assertWrite() {
        when(payload.readStringNul()).thenReturn("tbl");
        when(payload.readStringEOF()).thenReturn("-");
        ComFieldListPacket actual = new ComFieldListPacket(1, 1000, ShardingConstant.LOGIC_SCHEMA_NAME, payload, backendConnection);
        assertThat(actual.getSequenceId(), is(1));
        actual.write(payload);
        verify(payload).writeInt1(CommandPacketType.COM_FIELD_LIST.getValue());
        verify(payload).writeStringNul("tbl");
        verify(payload).writeStringEOF("-");
    }
    
    @Test
    public void assertExecuteWhenSuccess() throws SQLException {
        when(payload.readStringNul()).thenReturn("tbl");
        when(payload.readStringEOF()).thenReturn("-");
        when(backendHandler.next()).thenReturn(true, false);
        when(backendHandler.getResultValue()).thenReturn(new ResultPacket(1, Collections.<Object>singletonList("id"), 1, Collections.singletonList(ColumnType.MYSQL_TYPE_VARCHAR)));
        when(backendHandler.execute()).thenReturn(new CommandResponsePackets(new FieldCountPacket(1, 1)));
        ComFieldListPacket packet = new ComFieldListPacket(1, 1000, ShardingConstant.LOGIC_SCHEMA_NAME, payload, backendConnection);
        setBackendHandler(packet);
        Optional<CommandResponsePackets> actual = packet.execute();
        assertTrue(actual.isPresent());
        assertThat(actual.get().getPackets().size(), is(2));
        Iterator<DatabasePacket> databasePackets = actual.get().getPackets().iterator();
        assertColumnDefinition41Packet((ColumnDefinition41Packet) databasePackets.next());
        assertEofPacket((EofPacket) databasePackets.next());
    }
    
    private void assertColumnDefinition41Packet(final ColumnDefinition41Packet actual) {
        assertThat(actual.getSequenceId(), is(1));
        assertThat(actual.getName(), is("id"));
        assertThat(actual.getColumnType(), is(ColumnType.MYSQL_TYPE_VARCHAR));
    }
    
    private void assertEofPacket(final EofPacket actual) {
        assertThat(actual.getSequenceId(), is(2));
    }
    
    @Test
    public void assertExecuteWhenFailure() throws SQLException {
        when(payload.readStringNul()).thenReturn("tbl");
        when(payload.readStringEOF()).thenReturn("-");
        CommandResponsePackets expected = new CommandResponsePackets(new ErrPacket(1, ServerErrorCode.ER_STD_UNKNOWN_EXCEPTION, "unknown"));
        when(backendHandler.execute()).thenReturn(expected);
        ComFieldListPacket packet = new ComFieldListPacket(1, 1000, ShardingConstant.LOGIC_SCHEMA_NAME, payload, backendConnection);
        setBackendHandler(packet);
        Optional<CommandResponsePackets> actual = packet.execute();
        assertTrue(actual.isPresent());
        assertThat(actual.get(), is(expected));
    }
    
    @SneakyThrows
    private void setBackendHandler(final ComFieldListPacket packet) {
        Field field = ComFieldListPacket.class.getDeclaredField("backendHandler");
        field.setAccessible(true);
        field.set(packet, backendHandler);
    }
}

@@ -804,16 +804,164 @@
 nstant;%0A
+import io.shardingsphere.core.constant.properties.ShardingProperties;%0Aimport io.shardingsphere.core.constant.properties.ShardingPropertiesConstant;%0A
 import i
@@ -1015,16 +1015,16 @@
 andler;%0A
-
 import i
@@ -1154,24 +1154,87 @@
 Connection;%0A
+import io.shardingsphere.shardingproxy.runtime.GlobalRegistry;%0A
 import io.sh
@@ -2353,16 +2353,45 @@
 terator;
+%0Aimport java.util.Properties;
 %0A%0Aimport
@@ -2802,32 +2802,32 @@
 %0A    %0A    @Mock%0A
-
     private Back
@@ -2854,24 +2854,493 @@
 ndler;%0A    %0A
+    private void setMaxConnectionsSizePerQuery() throws ReflectiveOperationException %7B%0A        Field field = GlobalRegistry.getInstance().getClass().getDeclaredField(%22shardingProperties%22);%0A        field.setAccessible(true);%0A        Properties props = new Properties();%0A        props.setProperty(ShardingPropertiesConstant.PROXY_TRANSACTION_ENABLED.getKey(), String.valueOf(1));%0A        field.set(GlobalRegistry.getInstance(), new ShardingProperties(props));%0A    %7D%0A    %0A
     @Test%0A  

ADD setMaxConnectionsSizePerQuery()