package com.github.ambry.network;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Random;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;


public class SSLBlockingChannelTest {
  private static SSLFactory sslFactory;
  private static SSLSocketFactory sslSocketFactory;
  private static SSLBlockingEchoServer sslEchoServer;
  private static String hostName = "localhost";
  private static int sslPort = 18284;

  @BeforeClass
  public static void onceExecutedBeforeAll()
      throws Exception {
    sslFactory = TestUtils.createSSLFactory();
    SSLContext sslContext = sslFactory.createSSLContext();
    sslSocketFactory = sslContext.getSocketFactory();
    sslEchoServer = new SSLBlockingEchoServer(sslFactory, sslPort);
    sslEchoServer.start();
  }

  @AfterClass
  public static void onceExecutedAfterAll()
      throws Exception {
    int serverExceptionCount = sslEchoServer.getExceptionCount();
    assertEquals(serverExceptionCount, 0);
    sslEchoServer.close();
  }

  @Before
  public void setup()
      throws Exception {
  }

  @After
  public void teardown()
      throws Exception {
  }

  @Test
  public void testSendAndReceive()
      throws Exception {
    long blobSize = 1028;
    BlockingChannel channel = new SSLBlockingChannel(hostName, sslPort, 10000, 10000, 10000, 2000, sslSocketFactory);
    byte[] bytesToSend = new byte[(int) blobSize];
    new Random().nextBytes(bytesToSend);
    ByteBuffer byteBufferToSend = ByteBuffer.wrap(bytesToSend);
    byteBufferToSend.putLong(0, blobSize);
    BoundedByteBufferSend bufferToSend = new BoundedByteBufferSend(byteBufferToSend);
    // send request
    channel.connect();
    channel.send(bufferToSend);
    // receive response
    InputStream streamResponse = channel.receive().getInputStream();
    DataInputStream input = new DataInputStream(streamResponse);
    byte[] bytesReceived = new byte[(int) blobSize - 8];
    input.readFully(bytesReceived);
    for (int i = 0; i < blobSize - 8; i++) {
      Assert.assertEquals(bytesToSend[8 + i], bytesReceived[i]);
    }
    channel.disconnect();
  }

  @Test
  public void testWrongPortConnection()
      throws Exception {
    BlockingChannel channel =
        new SSLBlockingChannel(hostName, sslPort + 1, 10000, 10000, 10000, 2000, sslSocketFactory);
    try {
      // send request
      channel.connect();
      fail("should have thrown!");
    } catch (IOException e) {
      assertEquals(e.getMessage(), "Connection refused");
    }
  }
}

@@ -1520,34 +1520,8 @@
 n %7B%0A
-    long blobSize = 1028;%0A
     
@@ -1630,24 +1630,879 @@
 etFactory);%0A
+    sendAndReceive(channel);%0A    channel.disconnect();%0A  %7D%0A%0A  @Test%0A  public void testRenegotiation() throws Exception %7B%0A    BlockingChannel channel = new SSLBlockingChannel(hostName, sslPort, 10000, 10000, 10000, 2000, sslSocketFactory);%0A    sendAndReceive(channel);%0A    sslEchoServer.renegotiate();%0A    sendAndReceive(channel);%0A    channel.disconnect();%0A  %7D%0A%0A  @Test%0A  public void testWrongPortConnection()%0A      throws Exception %7B%0A    BlockingChannel channel =%0A        new SSLBlockingChannel(hostName, sslPort + 1, 10000, 10000, 10000, 2000, sslSocketFactory);%0A    try %7B%0A      // send request%0A      channel.connect();%0A      fail(%22should have thrown!%22);%0A    %7D catch (IOException e) %7B%0A      assertEquals(e.getMessage(), %22Connection refused%22);%0A    %7D%0A  %7D%0A%0A  private void sendAndReceive(BlockingChannel channel) throws Exception %7B%0A    long blobSize = 1028;%0A
     byte%5B%5D b
@@ -3220,428 +3220,8 @@
   %7D%0A
-    channel.disconnect();%0A  %7D%0A%0A  @Test%0A  public void testWrongPortConnection()%0A      throws Exception %7B%0A    BlockingChannel channel =%0A        new SSLBlockingChannel(hostName, sslPort + 1, 10000, 10000, 10000, 2000, sslSocketFactory);%0A    try %7B%0A      // send request%0A      channel.connect();%0A      fail(%22should have thrown!%22);%0A    %7D catch (IOException e) %7B%0A      assertEquals(e.getMessage(), %22Connection refused%22);%0A    %7D%0A
   %7D%0A

add a unit testcase for server renegotiation