/**
   * This test makes sure that even when the decoder is confronted with various chunk sizes in the
   * middle of decoding, it can recover and decode all the time eventually.
   */
  @Test
  public void shouldHandleNonUniformNetworkBatches() {
    ByteBuf incoming = Unpooled.copiedBuffer(SET_REQUEST_WITH_CONTENT);
    while (incoming.isReadable()) {
      channel.writeInbound(incoming.readBytes(5));
    }

    BinaryMemcacheRequest request = (BinaryMemcacheRequest) channel.readInbound();

    assertThat(request, notNullValue());
    assertThat(request.getHeader(), notNullValue());
    assertThat(request.getKey(), notNullValue());
    assertThat(request.getExtras(), nullValue());

    request.release();

    MemcacheContent content1 = (MemcacheContent) channel.readInbound();
    MemcacheContent content2 = (MemcacheContent) channel.readInbound();

    assertThat(content1, instanceOf(MemcacheContent.class));
    assertThat(content2, instanceOf(LastMemcacheContent.class));

    assertThat(content1.content().readableBytes(), is(3));
    assertThat(content2.content().readableBytes(), is(5));

    content1.release();
    content2.release();
  }
  /**
   * This test makes sure that even when more requests arrive in the same batch, they get emitted as
   * separate messages.
   */
  @Test
  public void shouldHandleTwoMessagesInOneBatch() {
    channel.writeInbound(Unpooled.buffer().writeBytes(GET_REQUEST).writeBytes(GET_REQUEST));

    BinaryMemcacheRequest request = (BinaryMemcacheRequest) channel.readInbound();
    assertThat(request, instanceOf(BinaryMemcacheRequest.class));
    assertThat(request, notNullValue());
    request.release();

    Object lastContent = channel.readInbound();
    assertThat(lastContent, instanceOf(LastMemcacheContent.class));
    ((ReferenceCounted) lastContent).release();

    request = (BinaryMemcacheRequest) channel.readInbound();
    assertThat(request, instanceOf(BinaryMemcacheRequest.class));
    assertThat(request, notNullValue());
    request.release();

    lastContent = channel.readInbound();
    assertThat(lastContent, instanceOf(LastMemcacheContent.class));
    ((ReferenceCounted) lastContent).release();
  }
  /** This tests a simple GET request with a key as the value. */
  @Test
  public void shouldDecodeRequestWithSimpleValue() {
    ByteBuf incoming = Unpooled.buffer();
    incoming.writeBytes(GET_REQUEST);
    channel.writeInbound(incoming);

    BinaryMemcacheRequest request = (BinaryMemcacheRequest) channel.readInbound();

    assertThat(request, notNullValue());
    assertThat(request.getHeader(), notNullValue());
    assertThat(request.getKey(), notNullValue());
    assertThat(request.getExtras(), nullValue());

    BinaryMemcacheRequestHeader header = request.getHeader();
    assertThat(header.getKeyLength(), is((short) 3));
    assertThat(header.getExtrasLength(), is((byte) 0));
    assertThat(header.getTotalBodyLength(), is(3));

    request.release();
    assertThat(channel.readInbound(), instanceOf(LastMemcacheContent.class));
  }
  /** This test makes sure that large content is emitted in chunks. */
  @Test
  public void shouldDecodeRequestWithChunkedContent() {
    int smallBatchSize = 2;
    channel = new EmbeddedChannel(new BinaryMemcacheRequestDecoder(smallBatchSize));

    ByteBuf incoming = Unpooled.buffer();
    incoming.writeBytes(SET_REQUEST_WITH_CONTENT);
    channel.writeInbound(incoming);

    BinaryMemcacheRequest request = (BinaryMemcacheRequest) channel.readInbound();

    assertThat(request, notNullValue());
    assertThat(request.getHeader(), notNullValue());
    assertThat(request.getKey(), notNullValue());
    assertThat(request.getExtras(), nullValue());

    BinaryMemcacheRequestHeader header = request.getHeader();
    assertThat(header.getKeyLength(), is((short) 3));
    assertThat(header.getExtrasLength(), is((byte) 0));
    assertThat(header.getTotalBodyLength(), is(11));

    request.release();

    int expectedContentChunks = 4;
    for (int i = 1; i <= expectedContentChunks; i++) {
      MemcacheContent content = (MemcacheContent) channel.readInbound();
      if (i < expectedContentChunks) {
        assertThat(content, instanceOf(MemcacheContent.class));
      } else {
        assertThat(content, instanceOf(LastMemcacheContent.class));
      }
      assertThat(content.content().readableBytes(), is(2));
      content.release();
    }
    assertThat(channel.readInbound(), nullValue());
  }