/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You 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.
 */
package org.apache.geode.internal.net;

import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED;
import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_TASK;
import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP;
import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW;
import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW;
import static javax.net.ssl.SSLEngineResult.Status.CLOSED;
import static javax.net.ssl.SSLEngineResult.Status.OK;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;

import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import org.apache.geode.GemFireIOException;
import org.apache.geode.distributed.internal.DMStats;
import org.apache.geode.test.junit.categories.MembershipTest;

@Category({MembershipTest.class})
public class NioSslEngineTest {
  private static final int netBufferSize = 10000;
  private static final int appBufferSize = 20000;

  private SSLEngine mockEngine;
  private DMStats mockStats;
  private NioSslEngine nioSslEngine;
  private NioSslEngine spyNioSslEngine;

  @Before
  public void setUp() throws Exception {
    mockEngine = mock(SSLEngine.class);

    SSLSession mockSession = mock(SSLSession.class);
    when(mockEngine.getSession()).thenReturn(mockSession);
    when(mockSession.getPacketBufferSize()).thenReturn(netBufferSize);
    when(mockSession.getApplicationBufferSize()).thenReturn(appBufferSize);

    mockStats = mock(DMStats.class);

    nioSslEngine = new NioSslEngine(mockEngine, new BufferPool(mockStats));
    spyNioSslEngine = spy(nioSslEngine);
  }

  @Test
  public void handshake() throws Exception {
    SocketChannel mockChannel = mock(SocketChannel.class);
    when(mockChannel.read(any(ByteBuffer.class))).thenReturn(100, 100, 100, 0);
    Socket mockSocket = mock(Socket.class);
    when(mockChannel.socket()).thenReturn(mockSocket);
    when(mockSocket.isClosed()).thenReturn(false);

    // initial read of handshake status followed by read of handshake status after task execution
    when(mockEngine.getHandshakeStatus()).thenReturn(NEED_UNWRAP, NEED_WRAP);

    // interleaved wraps/unwraps/task-execution
    when(mockEngine.unwrap(any(ByteBuffer.class), any(ByteBuffer.class))).thenReturn(
        new SSLEngineResult(OK, NEED_WRAP, 100, 100),
        new SSLEngineResult(BUFFER_OVERFLOW, NEED_UNWRAP, 0, 0),
        new SSLEngineResult(OK, NEED_TASK, 100, 0));

    when(mockEngine.getDelegatedTask()).thenReturn(() -> {
    }, (Runnable) null);

    when(mockEngine.wrap(any(ByteBuffer.class), any(ByteBuffer.class))).thenReturn(
        new SSLEngineResult(OK, NEED_UNWRAP, 100, 100),
        new SSLEngineResult(BUFFER_OVERFLOW, NEED_WRAP, 0, 0),
        new SSLEngineResult(CLOSED, FINISHED, 100, 0));

    spyNioSslEngine.handshake(mockChannel, 10000, ByteBuffer.allocate(netBufferSize / 2));
    verify(mockEngine, atLeast(2)).getHandshakeStatus();
    verify(mockEngine, times(3)).wrap(any(ByteBuffer.class), any(ByteBuffer.class));
    verify(mockEngine, times(3)).unwrap(any(ByteBuffer.class), any(ByteBuffer.class));
    verify(spyNioSslEngine, times(2)).expandWriteBuffer(any(BufferPool.BufferType.class),
        any(ByteBuffer.class), any(Integer.class));
    verify(spyNioSslEngine, times(1)).handleBlockingTasks();
    verify(mockChannel, times(3)).read(any(ByteBuffer.class));
  }

  @Test
  public void handshakeUsesBufferParameter() throws Exception {
    SocketChannel mockChannel = mock(SocketChannel.class);
    when(mockChannel.read(any(ByteBuffer.class))).thenReturn(100, 100, 100, 0);
    Socket mockSocket = mock(Socket.class);
    when(mockChannel.socket()).thenReturn(mockSocket);
    when(mockSocket.isClosed()).thenReturn(false);

    // initial read of handshake status followed by read of handshake status after task execution
    when(mockEngine.getHandshakeStatus()).thenReturn(NEED_UNWRAP, NEED_WRAP);

    // interleaved wraps/unwraps/task-execution
    when(mockEngine.unwrap(any(ByteBuffer.class), any(ByteBuffer.class))).thenReturn(
        new SSLEngineResult(OK, NEED_WRAP, 100, 100),
        new SSLEngineResult(BUFFER_OVERFLOW, NEED_UNWRAP, 0, 0),
        new SSLEngineResult(OK, NEED_TASK, 100, 0));

    when(mockEngine.getDelegatedTask()).thenReturn(() -> {
    }, (Runnable) null);

    when(mockEngine.wrap(any(ByteBuffer.class), any(ByteBuffer.class))).thenReturn(
        new SSLEngineResult(OK, NEED_UNWRAP, 100, 100),
        new SSLEngineResult(BUFFER_OVERFLOW, NEED_WRAP, 0, 0),
        new SSLEngineResult(CLOSED, FINISHED, 100, 0));

    ByteBuffer byteBuffer = ByteBuffer.allocate(netBufferSize);

    spyNioSslEngine.handshake(mockChannel, 10000, byteBuffer);

    assertThat(spyNioSslEngine.handshakeBuffer).isSameAs(byteBuffer);
  }


  @Test
  public void handshakeDetectsClosedSocket() throws Exception {
    SocketChannel mockChannel = mock(SocketChannel.class);
    when(mockChannel.read(any(ByteBuffer.class))).thenReturn(100, 100, 100, 0);
    Socket mockSocket = mock(Socket.class);
    when(mockChannel.socket()).thenReturn(mockSocket);
    when(mockSocket.isClosed()).thenReturn(true);

    // initial read of handshake status followed by read of handshake status after task execution
    when(mockEngine.getHandshakeStatus()).thenReturn(NEED_UNWRAP);

    ByteBuffer byteBuffer = ByteBuffer.allocate(netBufferSize);

    assertThatThrownBy(() -> spyNioSslEngine.handshake(mockChannel, 10000, byteBuffer))
        .isInstanceOf(
            SocketException.class)
        .hasMessageContaining("handshake terminated");
  }

  @Test
  public void handshakeDoesNotTerminateWithFinished() throws Exception {
    SocketChannel mockChannel = mock(SocketChannel.class);
    when(mockChannel.read(any(ByteBuffer.class))).thenReturn(100, 100, 100, 0);
    Socket mockSocket = mock(Socket.class);
    when(mockChannel.socket()).thenReturn(mockSocket);
    when(mockSocket.isClosed()).thenReturn(false);

    // initial read of handshake status followed by read of handshake status after task execution
    when(mockEngine.getHandshakeStatus()).thenReturn(NEED_UNWRAP);

    // interleaved wraps/unwraps/task-execution
    when(mockEngine.unwrap(any(ByteBuffer.class), any(ByteBuffer.class))).thenReturn(
        new SSLEngineResult(OK, NEED_WRAP, 100, 100));

    when(mockEngine.wrap(any(ByteBuffer.class), any(ByteBuffer.class))).thenReturn(
        new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 100, 0));

    ByteBuffer byteBuffer = ByteBuffer.allocate(netBufferSize);

    assertThatThrownBy(() -> spyNioSslEngine.handshake(mockChannel, 10000, byteBuffer))
        .isInstanceOf(
            SSLHandshakeException.class)
        .hasMessageContaining("SSL Handshake terminated with status");
  }


  @Test
  public void checkClosed() {
    nioSslEngine.checkClosed();
  }

  @Test(expected = IllegalStateException.class)
  public void checkClosedThrows() throws Exception {
    when(mockEngine.wrap(any(ByteBuffer.class), any(ByteBuffer.class))).thenReturn(
        new SSLEngineResult(CLOSED, FINISHED, 0, 100));
    nioSslEngine.close(mock(SocketChannel.class));
    nioSslEngine.checkClosed();
  }

  @Test
  public void wrap() throws Exception {
    // make the application data too big to fit into the engine's encryption buffer
    ByteBuffer appData = ByteBuffer.allocate(nioSslEngine.myNetData.capacity() + 100);
    byte[] appBytes = new byte[appData.capacity()];
    Arrays.fill(appBytes, (byte) 0x1F);
    appData.put(appBytes);
    appData.flip();

    // create an engine that will transfer bytes from the application buffer to the encrypted buffer
    TestSSLEngine testEngine = new TestSSLEngine();
    testEngine.addReturnResult(
        new SSLEngineResult(OK, NEED_TASK, appData.remaining(), appData.remaining()));
    spyNioSslEngine.engine = testEngine;

    ByteBuffer wrappedBuffer = spyNioSslEngine.wrap(appData);

    verify(spyNioSslEngine, times(1)).expandWriteBuffer(any(BufferPool.BufferType.class),
        any(ByteBuffer.class), any(Integer.class));
    appData.flip();
    assertThat(wrappedBuffer).isEqualTo(appData);
    verify(spyNioSslEngine, times(1)).handleBlockingTasks();
  }

  @Test
  public void wrapFails() {
    // make the application data too big to fit into the engine's encryption buffer
    ByteBuffer appData = ByteBuffer.allocate(nioSslEngine.myNetData.capacity() + 100);
    byte[] appBytes = new byte[appData.capacity()];
    Arrays.fill(appBytes, (byte) 0x1F);
    appData.put(appBytes);
    appData.flip();

    // create an engine that will transfer bytes from the application buffer to the encrypted buffer
    TestSSLEngine testEngine = new TestSSLEngine();
    testEngine.addReturnResult(
        new SSLEngineResult(CLOSED, NEED_TASK, appData.remaining(), appData.remaining()));
    spyNioSslEngine.engine = testEngine;

    assertThatThrownBy(() -> spyNioSslEngine.wrap(appData)).isInstanceOf(SSLException.class)
        .hasMessageContaining("Error encrypting data");
  }

  @Test
  public void unwrapWithBufferOverflow() throws Exception {
    // make the application data too big to fit into the engine's encryption buffer
    ByteBuffer wrappedData = ByteBuffer.allocate(nioSslEngine.peerAppData.capacity() + 100);
    byte[] netBytes = new byte[wrappedData.capacity()];
    Arrays.fill(netBytes, (byte) 0x1F);
    wrappedData.put(netBytes);
    wrappedData.flip();

    // create an engine that will transfer bytes from the application buffer to the encrypted buffer
    TestSSLEngine testEngine = new TestSSLEngine();
    spyNioSslEngine.engine = testEngine;

    testEngine.addReturnResult(
        new SSLEngineResult(BUFFER_OVERFLOW, NEED_UNWRAP, netBytes.length, netBytes.length),
        new SSLEngineResult(OK, FINISHED, netBytes.length, netBytes.length));

    ByteBuffer unwrappedBuffer = spyNioSslEngine.unwrap(wrappedData);
    unwrappedBuffer.flip();

    verify(spyNioSslEngine, times(2)).expandPeerAppData(any(ByteBuffer.class));
    assertThat(unwrappedBuffer).isEqualTo(ByteBuffer.wrap(netBytes));
  }

  @Test
  public void unwrapWithBufferUnderflow() throws Exception {
    ByteBuffer wrappedData = ByteBuffer.allocate(nioSslEngine.peerAppData.capacity());
    byte[] netBytes = new byte[wrappedData.capacity() / 2];
    Arrays.fill(netBytes, (byte) 0x1F);
    wrappedData.put(netBytes);
    wrappedData.flip();

    // create an engine that will transfer bytes from the application buffer to the encrypted buffer
    TestSSLEngine testEngine = new TestSSLEngine();
    testEngine.addReturnResult(new SSLEngineResult(BUFFER_UNDERFLOW, NEED_TASK, 0, 0));
    spyNioSslEngine.engine = testEngine;

    ByteBuffer unwrappedBuffer = spyNioSslEngine.unwrap(wrappedData);
    unwrappedBuffer.flip();
    assertThat(unwrappedBuffer.remaining()).isEqualTo(0);
    assertThat(wrappedData.position()).isEqualTo(netBytes.length);
  }

  @Test
  public void unwrapWithDecryptionError() {
    // make the application data too big to fit into the engine's encryption buffer
    ByteBuffer wrappedData = ByteBuffer.allocate(nioSslEngine.peerAppData.capacity());
    byte[] netBytes = new byte[wrappedData.capacity() / 2];
    Arrays.fill(netBytes, (byte) 0x1F);
    wrappedData.put(netBytes);
    wrappedData.flip();

    // create an engine that will transfer bytes from the application buffer to the encrypted buffer
    TestSSLEngine testEngine = new TestSSLEngine();
    testEngine.addReturnResult(new SSLEngineResult(CLOSED, FINISHED, 0, 0));
    spyNioSslEngine.engine = testEngine;

    assertThatThrownBy(() -> spyNioSslEngine.unwrap(wrappedData)).isInstanceOf(SSLException.class)
        .hasMessageContaining("Error decrypting data");
  }

  @Test
  public void ensureUnwrappedCapacity() {
    ByteBuffer wrappedBuffer = ByteBuffer.allocate(netBufferSize);
    int requestedCapacity = nioSslEngine.getUnwrappedBuffer(wrappedBuffer).capacity() * 2;
    ByteBuffer unwrappedBuffer = nioSslEngine.ensureUnwrappedCapacity(requestedCapacity);
    assertThat(unwrappedBuffer.capacity()).isGreaterThanOrEqualTo(requestedCapacity);
  }

  @Test
  public void close() throws Exception {
    SocketChannel mockChannel = mock(SocketChannel.class);
    Socket mockSocket = mock(Socket.class);
    when(mockChannel.socket()).thenReturn(mockSocket);
    when(mockSocket.isClosed()).thenReturn(false);

    when(mockEngine.isOutboundDone()).thenReturn(Boolean.FALSE);
    when(mockEngine.wrap(any(ByteBuffer.class), any(ByteBuffer.class))).thenReturn(
        new SSLEngineResult(CLOSED, FINISHED, 0, 0));
    nioSslEngine.close(mockChannel);
    assertThatThrownBy(() -> nioSslEngine.checkClosed()).isInstanceOf(IllegalStateException.class);
    nioSslEngine.close(mockChannel);
  }

  @Test
  public void closeWhenUnwrapError() throws Exception {
    SocketChannel mockChannel = mock(SocketChannel.class);
    Socket mockSocket = mock(Socket.class);
    when(mockChannel.socket()).thenReturn(mockSocket);
    when(mockSocket.isClosed()).thenReturn(true);

    when(mockEngine.isOutboundDone()).thenReturn(Boolean.FALSE);
    when(mockEngine.wrap(any(ByteBuffer.class), any(ByteBuffer.class))).thenReturn(
        new SSLEngineResult(BUFFER_OVERFLOW, FINISHED, 0, 0));
    assertThatThrownBy(() -> nioSslEngine.close(mockChannel)).isInstanceOf(GemFireIOException.class)
        .hasMessageContaining("exception closing SSL session")
        .hasCauseInstanceOf(SSLException.class);
  }

  @Test
  public void closeWhenSocketWriteError() throws Exception {
    SocketChannel mockChannel = mock(SocketChannel.class);
    Socket mockSocket = mock(Socket.class);
    when(mockChannel.socket()).thenReturn(mockSocket);
    when(mockSocket.isClosed()).thenReturn(true);

    when(mockEngine.isOutboundDone()).thenReturn(Boolean.FALSE);
    when(mockEngine.wrap(any(ByteBuffer.class), any(ByteBuffer.class))).thenAnswer((x) -> {
      // give the NioSslEngine something to write on its socket channel, simulating a TLS close
      // message
      nioSslEngine.myNetData.put("Goodbye cruel world".getBytes());
      return new SSLEngineResult(CLOSED, FINISHED, 0, 0);
    });
    when(mockChannel.write(any(ByteBuffer.class))).thenThrow(new ClosedChannelException());
    nioSslEngine.close(mockChannel);
    verify(mockChannel, times(1)).write(any(ByteBuffer.class));
  }

  @Test
  public void ensureWrappedCapacityOfSmallMessage() {
    ByteBuffer buffer = ByteBuffer.allocate(netBufferSize);
    assertThat(
        nioSslEngine.ensureWrappedCapacity(10, buffer, BufferPool.BufferType.UNTRACKED))
            .isEqualTo(buffer);
  }

  @Test
  public void ensureWrappedCapacityWithNoBuffer() {
    assertThat(
        nioSslEngine.ensureWrappedCapacity(10, null, BufferPool.BufferType.UNTRACKED)
            .capacity())
                .isEqualTo(netBufferSize);
  }

  @Test
  public void readAtLeast() throws Exception {
    final int amountToRead = 150;
    final int individualRead = 60;
    final int preexistingBytes = 10;
    ByteBuffer wrappedBuffer = ByteBuffer.allocate(1000);
    SocketChannel mockChannel = mock(SocketChannel.class);

    // force a compaction by making the decoded buffer appear near to being full
    ByteBuffer unwrappedBuffer = nioSslEngine.peerAppData;
    unwrappedBuffer.position(unwrappedBuffer.capacity() - individualRead);
    unwrappedBuffer.limit(unwrappedBuffer.position() + preexistingBytes);

    // simulate some socket reads
    when(mockChannel.read(any(ByteBuffer.class))).thenAnswer(new Answer<Integer>() {
      @Override
      public Integer answer(InvocationOnMock invocation) throws Throwable {
        ByteBuffer buffer = invocation.getArgument(0);
        buffer.position(buffer.position() + individualRead);
        return individualRead;
      }
    });

    TestSSLEngine testSSLEngine = new TestSSLEngine();
    testSSLEngine.addReturnResult(new SSLEngineResult(OK, NEED_UNWRAP, 0, 0));
    nioSslEngine.engine = testSSLEngine;

    ByteBuffer data = nioSslEngine.readAtLeast(mockChannel, amountToRead, wrappedBuffer);
    verify(mockChannel, times(3)).read(isA(ByteBuffer.class));
    assertThat(data.position()).isEqualTo(0);
    assertThat(data.limit()).isEqualTo(individualRead * 3 + preexistingBytes);
  }


  /**
   * This tests the case where a message header has been read and part of a message has been
   * read, but the decoded buffer is too small to hold all of the message. In this case
   * the readAtLeast method will have to expand the capacity of the decoded buffer and return
   * the new, expanded, buffer as the method result.
   */
  @Test
  public void readAtLeastUsingSmallAppBuffer() throws Exception {
    final int amountToRead = 150;
    final int individualRead = 60;
    final int preexistingBytes = 10;
    ByteBuffer wrappedBuffer = ByteBuffer.allocate(1000);
    SocketChannel mockChannel = mock(SocketChannel.class);

    // force buffer expansion by making a small decoded buffer appear near to being full
    ByteBuffer unwrappedBuffer = ByteBuffer.allocate(100);
    unwrappedBuffer.position(7).limit(preexistingBytes + 7); // 7 bytes of message header - ignored
    nioSslEngine.peerAppData = unwrappedBuffer;

    // simulate some socket reads
    when(mockChannel.read(any(ByteBuffer.class))).thenAnswer(new Answer<Integer>() {
      @Override
      public Integer answer(InvocationOnMock invocation) throws Throwable {
        ByteBuffer buffer = invocation.getArgument(0);
        buffer.position(buffer.position() + individualRead);
        return individualRead;
      }
    });

    TestSSLEngine testSSLEngine = new TestSSLEngine();
    testSSLEngine.addReturnResult(
        new SSLEngineResult(OK, NEED_UNWRAP, 0, 0), // 10 + 60 bytes = 70
        new SSLEngineResult(OK, NEED_UNWRAP, 0, 0), // 70 + 60 bytes = 130
        new SSLEngineResult(BUFFER_OVERFLOW, NEED_UNWRAP, 0, 0), // need 190 bytes capacity
        new SSLEngineResult(OK, NEED_UNWRAP, 0, 0)); // 130 + 60 bytes = 190
    nioSslEngine.engine = testSSLEngine;

    ByteBuffer data = nioSslEngine.readAtLeast(mockChannel, amountToRead, wrappedBuffer);
    verify(mockChannel, times(3)).read(isA(ByteBuffer.class));
    assertThat(data.position()).isEqualTo(0);
    assertThat(data.limit()).isEqualTo(individualRead * 3 + preexistingBytes);
  }


  // TestSSLEngine holds a stack of SSLEngineResults and always copies the
  // input buffer to the output buffer byte-for-byte in wrap() and unwrap() operations.
  // We use it in some tests where we need the byte-copying behavior because it's
  // pretty difficult & cumbersome to implement with Mockito.
  static class TestSSLEngine extends SSLEngine {

    private List<SSLEngineResult> returnResults = new ArrayList<>();

    private SSLEngineResult nextResult() {
      SSLEngineResult result = returnResults.remove(0);
      if (returnResults.isEmpty()) {
        returnResults.add(result);
      }
      return result;
    }

    @Override
    public SSLEngineResult wrap(ByteBuffer[] sources, int i, int i1, ByteBuffer destination) {
      for (ByteBuffer source : sources) {
        destination.put(source);
      }
      return nextResult();
    }

    @Override
    public SSLEngineResult unwrap(ByteBuffer source, ByteBuffer[] destinations, int i, int i1) {
      SSLEngineResult sslEngineResult = nextResult();
      if (sslEngineResult.getStatus() != BUFFER_UNDERFLOW
          && sslEngineResult.getStatus() != BUFFER_OVERFLOW) {
        destinations[0].put(source);
      }
      return sslEngineResult;
    }

    @Override
    public Runnable getDelegatedTask() {
      return null;
    }

    @Override
    public void closeInbound() {}

    @Override
    public boolean isInboundDone() {
      return false;
    }

    @Override
    public void closeOutbound() {}

    @Override
    public boolean isOutboundDone() {
      return false;
    }

    @Override
    public String[] getSupportedCipherSuites() {
      return new String[0];
    }

    @Override
    public String[] getEnabledCipherSuites() {
      return new String[0];
    }

    @Override
    public void setEnabledCipherSuites(String[] strings) {}

    @Override
    public String[] getSupportedProtocols() {
      return new String[0];
    }

    @Override
    public String[] getEnabledProtocols() {
      return new String[0];
    }

    @Override
    public void setEnabledProtocols(String[] strings) {}

    @Override
    public SSLSession getSession() {
      return null;
    }

    @Override
    public void beginHandshake() {}

    @Override
    public SSLEngineResult.HandshakeStatus getHandshakeStatus() {
      return null;
    }

    @Override
    public void setUseClientMode(boolean b) {}

    @Override
    public boolean getUseClientMode() {
      return false;
    }

    @Override
    public void setNeedClientAuth(boolean b) {}

    @Override
    public boolean getNeedClientAuth() {
      return false;
    }

    @Override
    public void setWantClientAuth(boolean b) {}

    @Override
    public boolean getWantClientAuth() {
      return false;
    }

    @Override
    public void setEnableSessionCreation(boolean b) {}

    @Override
    public boolean getEnableSessionCreation() {
      return false;
    }

    /**
     * add an engine operation result to be returned by wrap or unwrap.
     * Like Mockito's thenReturn(), the last return result will repeat forever
     */
    void addReturnResult(SSLEngineResult... sslEngineResult) {
      for (SSLEngineResult result : sslEngineResult) {
        returnResults.add(result);
      }
    }
  }
}
