io.reactivesocket.FrameTest.java Source code

Java tutorial

Introduction

Here is the source code for io.reactivesocket.FrameTest.java

Source

/**
 * Copyright 2015 Netflix, Inc.
 * <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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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 io.reactivesocket;

import io.netty.buffer.ByteBufUtil;
import io.reactivesocket.exceptions.Exceptions;
import io.reactivesocket.exceptions.RejectedException;
import io.reactivesocket.internal.frame.SetupFrameFlyweight;
import org.agrona.concurrent.UnsafeBuffer;
import org.junit.Test;
import org.junit.experimental.theories.DataPoint;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;

import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;

import static io.reactivesocket.internal.frame.ErrorFrameFlyweight.REJECTED;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;

@RunWith(Theories.class)
public class FrameTest {
    private static Payload createPayload(final ByteBuffer metadata, final ByteBuffer data) {
        return new Payload() {
            public ByteBuffer getData() {
                return data;
            }

            public ByteBuffer getMetadata() {
                return metadata;
            }
        };
    }

    @DataPoint
    public static final int ZERO_OFFSET = 0;

    @DataPoint
    public static final int NON_ZERO_OFFSET = 127;

    private static final UnsafeBuffer reusableMutableDirectBuffer = new UnsafeBuffer(ByteBuffer.allocate(1024));
    private static final Frame reusableFrame = Frame.allocate(reusableMutableDirectBuffer);

    @Test
    public void testWriteThenRead() {
        final ByteBuffer helloBuffer = TestUtil.byteBufferFromUtf8String("hello");
        final Payload payload = createPayload(Frame.NULL_BYTEBUFFER, helloBuffer);

        Frame f = Frame.Request.from(1, FrameType.REQUEST_RESPONSE, payload, 1);

        assertEquals("hello", TestUtil.byteToString(f.getData()));
        assertEquals(FrameType.REQUEST_RESPONSE, f.getType());
        assertEquals(1, f.getStreamId());

        ByteBuffer b = f.getByteBuffer();

        Frame f2 = Frame.from(b);
        assertEquals("hello", TestUtil.byteToString(f2.getData()));
        assertEquals(FrameType.REQUEST_RESPONSE, f2.getType());
        assertEquals(1, f2.getStreamId());
    }

    @Test
    public void testWrapMessage() {
        final ByteBuffer helloBuffer = TestUtil.byteBufferFromUtf8String("hello");
        final ByteBuffer doneBuffer = TestUtil.byteBufferFromUtf8String("done");
        final Payload payload = createPayload(Frame.NULL_BYTEBUFFER, helloBuffer);

        Frame f = Frame.Request.from(1, FrameType.REQUEST_RESPONSE, payload, 1);

        f.wrap(2, FrameType.COMPLETE, doneBuffer);
        assertEquals("done", TestUtil.byteToString(f.getData()));
        assertEquals(FrameType.NEXT_COMPLETE, f.getType());
        assertEquals(2, f.getStreamId());
    }

    @Test
    public void testWrapBytes() {
        final ByteBuffer helloBuffer = TestUtil.byteBufferFromUtf8String("hello");
        final ByteBuffer anotherBuffer = TestUtil.byteBufferFromUtf8String("another");
        final Payload payload = createPayload(Frame.NULL_BYTEBUFFER, helloBuffer);
        final Payload anotherPayload = createPayload(Frame.NULL_BYTEBUFFER, anotherBuffer);

        Frame f = Frame.Request.from(1, FrameType.REQUEST_RESPONSE, payload, 1);
        Frame f2 = Frame.Response.from(20, FrameType.COMPLETE, anotherPayload);

        ByteBuffer b = f2.getByteBuffer();
        f.wrap(b, 0);

        assertEquals("another", TestUtil.byteToString(f.getData()));
        assertEquals(FrameType.NEXT_COMPLETE, f.getType());
        assertEquals(20, f.getStreamId());
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataPlusMetadataForRequestResponse(final int offset) {
        final ByteBuffer requestData = TestUtil.byteBufferFromUtf8String("request data");
        final ByteBuffer requestMetadata = TestUtil.byteBufferFromUtf8String("request metadata");
        final Payload payload = createPayload(requestMetadata, requestData);

        Frame encodedFrame = Frame.Request.from(1, FrameType.REQUEST_RESPONSE, payload, 1);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals(FrameType.REQUEST_RESPONSE, reusableFrame.getType());
        assertEquals(1, reusableFrame.getStreamId());
        assertEquals("request data", TestUtil.byteToString(reusableFrame.getData()));
        assertEquals("request metadata", TestUtil.byteToString(reusableFrame.getMetadata()));

        assertEquals("0000002c0004400000000001", ByteBufUtil.hexDump(encodedFrame.getByteBuffer().array(), 0, 12));
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataPlusMetadataForFireAndForget(final int offset) {
        final ByteBuffer requestData = TestUtil.byteBufferFromUtf8String("request data");
        final ByteBuffer requestMetadata = TestUtil.byteBufferFromUtf8String("request metadata");
        final Payload payload = createPayload(requestMetadata, requestData);

        Frame encodedFrame = Frame.Request.from(1, FrameType.FIRE_AND_FORGET, payload, 0);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals("request data", TestUtil.byteToString(reusableFrame.getData()));
        assertEquals("request metadata", TestUtil.byteToString(reusableFrame.getMetadata()));
        assertEquals(FrameType.FIRE_AND_FORGET, reusableFrame.getType());
        assertEquals(1, reusableFrame.getStreamId());

        assertEquals("0000002c0005400000000001", ByteBufUtil.hexDump(encodedFrame.getByteBuffer().array(), 0, 12));
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataPlusMetadataForRequestStream(final int offset) {
        final ByteBuffer requestData = TestUtil.byteBufferFromUtf8String("request data");
        final ByteBuffer requestMetadata = TestUtil.byteBufferFromUtf8String("request metadata");
        final Payload payload = createPayload(requestMetadata, requestData);

        Frame encodedFrame = Frame.Request.from(1, FrameType.REQUEST_STREAM, payload, 128);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals("request data", TestUtil.byteToString(reusableFrame.getData()));
        assertEquals("request metadata", TestUtil.byteToString(reusableFrame.getMetadata()));
        assertEquals(FrameType.REQUEST_STREAM, reusableFrame.getType());
        assertEquals(1, reusableFrame.getStreamId());
        assertEquals(128, Frame.Request.initialRequestN(reusableFrame));

        assertEquals("000000300006480000000001", ByteBufUtil.hexDump(encodedFrame.getByteBuffer().array(), 0, 12));
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataPlusMetadataForRequestSubscription(final int offset) {
        final ByteBuffer requestData = TestUtil.byteBufferFromUtf8String("request data");
        final ByteBuffer requestMetadata = TestUtil.byteBufferFromUtf8String("request metadata");
        final Payload payload = createPayload(requestMetadata, requestData);

        Frame encodedFrame = Frame.Request.from(1, FrameType.REQUEST_SUBSCRIPTION, payload, 128);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals("request data", TestUtil.byteToString(reusableFrame.getData()));
        assertEquals("request metadata", TestUtil.byteToString(reusableFrame.getMetadata()));
        assertEquals(FrameType.REQUEST_SUBSCRIPTION, reusableFrame.getType());
        assertEquals(1, reusableFrame.getStreamId());
        assertEquals(128, Frame.Request.initialRequestN(reusableFrame));

        assertEquals("000000300007480000000001", ByteBufUtil.hexDump(encodedFrame.getByteBuffer().array(), 0, 12));
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataPlusMetadataForResponse(final int offset) {
        final ByteBuffer requestData = TestUtil.byteBufferFromUtf8String("response data");
        final ByteBuffer requestMetadata = TestUtil.byteBufferFromUtf8String("response metadata");
        final Payload payload = createPayload(requestMetadata, requestData);

        Frame encodedFrame = Frame.Response.from(1, FrameType.RESPONSE, payload);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals("response data", TestUtil.byteToString(reusableFrame.getData()));
        assertEquals("response metadata", TestUtil.byteToString(reusableFrame.getMetadata()));
        assertEquals(FrameType.NEXT, reusableFrame.getType());
        assertEquals(1, reusableFrame.getStreamId());

        assertEquals("0000002e000b400000000001", ByteBufUtil.hexDump(encodedFrame.getByteBuffer().array(), 0, 12));
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataWithoutMetadataForRequestResponse(final int offset) {
        final ByteBuffer requestData = TestUtil.byteBufferFromUtf8String("request data");
        final Payload payload = createPayload(Frame.NULL_BYTEBUFFER, requestData);

        Frame encodedFrame = Frame.Request.from(1, FrameType.REQUEST_RESPONSE, payload, 1);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals("request data", TestUtil.byteToString(reusableFrame.getData()));

        final ByteBuffer metadataBuffer = reusableFrame.getMetadata();
        assertEquals(0, metadataBuffer.remaining());
        assertEquals(FrameType.REQUEST_RESPONSE, reusableFrame.getType());
        assertEquals(1, reusableFrame.getStreamId());
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataWithoutMetadataForFireAndForget(final int offset) {
        final ByteBuffer requestData = TestUtil.byteBufferFromUtf8String("request data");
        final Payload payload = createPayload(Frame.NULL_BYTEBUFFER, requestData);

        Frame encodedFrame = Frame.Request.from(1, FrameType.FIRE_AND_FORGET, payload, 0);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals("request data", TestUtil.byteToString(reusableFrame.getData()));

        final ByteBuffer metadataBuffer = reusableFrame.getMetadata();
        assertEquals(0, metadataBuffer.remaining());
        assertEquals(FrameType.FIRE_AND_FORGET, reusableFrame.getType());
        assertEquals(1, reusableFrame.getStreamId());
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataWithoutMetadataForRequestStream(final int offset) {
        final ByteBuffer requestData = TestUtil.byteBufferFromUtf8String("request data");
        final Payload payload = createPayload(Frame.NULL_BYTEBUFFER, requestData);

        Frame encodedFrame = Frame.Request.from(1, FrameType.REQUEST_STREAM, payload, 128);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals("request data", TestUtil.byteToString(reusableFrame.getData()));

        final ByteBuffer metadataBuffer = reusableFrame.getMetadata();
        assertEquals(0, metadataBuffer.remaining());
        assertEquals(FrameType.REQUEST_STREAM, reusableFrame.getType());
        assertEquals(1, reusableFrame.getStreamId());
        assertEquals(128, Frame.Request.initialRequestN(reusableFrame));
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataWithoutMetadataForRequestSubscription(final int offset) {
        final ByteBuffer requestData = TestUtil.byteBufferFromUtf8String("request data");
        final Payload payload = createPayload(Frame.NULL_BYTEBUFFER, requestData);

        Frame encodedFrame = Frame.Request.from(1, FrameType.REQUEST_SUBSCRIPTION, payload, 128);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals("request data", TestUtil.byteToString(reusableFrame.getData()));

        final ByteBuffer metadataBuffer = reusableFrame.getMetadata();
        assertEquals(0, metadataBuffer.remaining());
        assertEquals(FrameType.REQUEST_SUBSCRIPTION, reusableFrame.getType());
        assertEquals(1, reusableFrame.getStreamId());
        assertEquals(128, Frame.Request.initialRequestN(reusableFrame));
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataWithoutMetadataForResponse(final int offset) {
        final ByteBuffer requestData = TestUtil.byteBufferFromUtf8String("response data");
        final Payload payload = createPayload(Frame.NULL_BYTEBUFFER, requestData);

        Frame encodedFrame = Frame.Response.from(1, FrameType.RESPONSE, payload);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals("response data", TestUtil.byteToString(reusableFrame.getData()));

        final ByteBuffer metadataBuffer = reusableFrame.getMetadata();
        assertEquals(0, metadataBuffer.remaining());
        assertEquals(FrameType.NEXT, reusableFrame.getType());
        assertEquals(1, reusableFrame.getStreamId());
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataPlusMetadataForSetup(final int offset) {
        final int flags = SetupFrameFlyweight.FLAGS_WILL_HONOR_LEASE
                | SetupFrameFlyweight.FLAGS_STRICT_INTERPRETATION;
        final int version = SetupFrameFlyweight.CURRENT_VERSION;
        final int keepaliveInterval = 1001;
        final int maxLifetime = keepaliveInterval * 5;
        final String metadataMimeType = "application/json";
        final String dataMimeType = "application/cbor";
        final ByteBuffer setupData = TestUtil.byteBufferFromUtf8String("setup data");
        final ByteBuffer setupMetadata = TestUtil.byteBufferFromUtf8String("setup metadata");

        Frame encodedFrame = Frame.Setup.from(flags, keepaliveInterval, maxLifetime, metadataMimeType, dataMimeType,
                new Payload() {
                    public ByteBuffer getData() {
                        return setupData;
                    }

                    public ByteBuffer getMetadata() {
                        return setupMetadata;
                    }
                });
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals(FrameType.SETUP, reusableFrame.getType());
        assertEquals(flags, Frame.Setup.getFlags(reusableFrame));
        assertEquals(version, Frame.Setup.version(reusableFrame));
        assertEquals(keepaliveInterval, Frame.Setup.keepaliveInterval(reusableFrame));
        assertEquals(maxLifetime, Frame.Setup.maxLifetime(reusableFrame));
        assertEquals(metadataMimeType, Frame.Setup.metadataMimeType(reusableFrame));
        assertEquals(dataMimeType, Frame.Setup.dataMimeType(reusableFrame));
        assertEquals("setup data", TestUtil.byteToString(reusableFrame.getData()));
        assertEquals("setup metadata", TestUtil.byteToString(reusableFrame.getMetadata()));
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataWithoutMetadataForSetup(final int offset) {
        final int flags = SetupFrameFlyweight.FLAGS_WILL_HONOR_LEASE
                | SetupFrameFlyweight.FLAGS_STRICT_INTERPRETATION;
        final int version = SetupFrameFlyweight.CURRENT_VERSION;
        final int keepaliveInterval = 1001;
        final int maxLifetime = keepaliveInterval * 5;
        final String metadataMimeType = "application/json";
        final String dataMimeType = "application/cbor";
        final ByteBuffer setupData = TestUtil.byteBufferFromUtf8String("setup data");

        Frame encodedFrame = Frame.Setup.from(flags, keepaliveInterval, maxLifetime, metadataMimeType, dataMimeType,
                new Payload() {
                    public ByteBuffer getData() {
                        return setupData;
                    }

                    public ByteBuffer getMetadata() {
                        return Frame.NULL_BYTEBUFFER;
                    }
                });
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals(FrameType.SETUP, reusableFrame.getType());
        assertEquals(flags, Frame.Setup.getFlags(reusableFrame));
        assertEquals(version, Frame.Setup.version(reusableFrame));
        assertEquals(keepaliveInterval, Frame.Setup.keepaliveInterval(reusableFrame));
        assertEquals(maxLifetime, Frame.Setup.maxLifetime(reusableFrame));
        assertEquals(metadataMimeType, Frame.Setup.metadataMimeType(reusableFrame));
        assertEquals(dataMimeType, Frame.Setup.dataMimeType(reusableFrame));
        assertEquals("setup data", TestUtil.byteToString(reusableFrame.getData()));
        assertEquals(Frame.NULL_BYTEBUFFER, reusableFrame.getMetadata());
    }

    @Test
    @Theory
    public void shouldFormCorrectlyWithoutDataNorMetadataForSetup(final int offset) {
        final int flags = SetupFrameFlyweight.FLAGS_WILL_HONOR_LEASE
                | SetupFrameFlyweight.FLAGS_STRICT_INTERPRETATION;
        final int version = SetupFrameFlyweight.CURRENT_VERSION;
        final int keepaliveInterval = 1001;
        final int maxLifetime = keepaliveInterval * 5;
        final String metadataMimeType = "application/json";
        final String dataMimeType = "application/cbor";

        Frame encodedFrame = Frame.Setup.from(flags, keepaliveInterval, maxLifetime, metadataMimeType, dataMimeType,
                new Payload() {
                    public ByteBuffer getData() {
                        return Frame.NULL_BYTEBUFFER;
                    }

                    public ByteBuffer getMetadata() {
                        return Frame.NULL_BYTEBUFFER;
                    }
                });
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals(FrameType.SETUP, reusableFrame.getType());
        assertEquals(flags, Frame.Setup.getFlags(reusableFrame));
        assertEquals(version, Frame.Setup.version(reusableFrame));
        assertEquals(keepaliveInterval, Frame.Setup.keepaliveInterval(reusableFrame));
        assertEquals(maxLifetime, Frame.Setup.maxLifetime(reusableFrame));
        assertEquals(metadataMimeType, Frame.Setup.metadataMimeType(reusableFrame));
        assertEquals(dataMimeType, Frame.Setup.dataMimeType(reusableFrame));
        assertEquals(Frame.NULL_BYTEBUFFER, reusableFrame.getData());
        assertEquals(Frame.NULL_BYTEBUFFER, reusableFrame.getMetadata());

        assertEquals("0000003a000130000000000000000000000003e90000138d",
                ByteBufUtil.hexDump(encodedFrame.getByteBuffer().array(), 0, 24));
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataPlusMetadataForError(final int offset) {
        final int streamId = 24;
        final Throwable exception = new RejectedException("test");
        final String data = "error data";
        final String metadata = "error metadata";
        final ByteBuffer dataByteBuffer = ByteBuffer.wrap(data.getBytes(UTF_8));
        final ByteBuffer metadataByteBuffer = ByteBuffer.wrap(metadata.getBytes(UTF_8));

        Frame encodedFrame = Frame.Error.from(streamId, exception, metadataByteBuffer, dataByteBuffer);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals(FrameType.ERROR, reusableFrame.getType());
        assertEquals(REJECTED, Frame.Error.errorCode(reusableFrame));
        assertEquals(data, TestUtil.byteToString(reusableFrame.getData()));
        assertEquals(metadata, TestUtil.byteToString(reusableFrame.getMetadata()));

        assertEquals("0000002c000c40000000001800000202",
                ByteBufUtil.hexDump(encodedFrame.getByteBuffer().array(), 0, 16));
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataWithThrowableForError(final int offset) {
        final int errorCode = 42;
        final String metadata = "my metadata";
        final String exMessage = "exception message";

        Frame encodedFrame = Frame.Error.from(errorCode, new Exception(exMessage),
                TestUtil.byteBufferFromUtf8String(metadata));
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals(FrameType.ERROR, reusableFrame.getType());
        assertEquals(exMessage, TestUtil.byteToString(reusableFrame.getData()));
        assertEquals(TestUtil.byteBufferFromUtf8String(metadata), reusableFrame.getMetadata());

        final Throwable throwable = Exceptions.from(encodedFrame);
        assertEquals(exMessage, throwable.getMessage());
    }

    @Test
    @Theory
    public void shouldReturnCorrectDataWithoutMetadataForError(final int offset) {
        final int errorCode = 42;
        final String metadata = "metadata";
        final String data = "error data";

        Frame encodedFrame = Frame.Error.from(errorCode, new Exception("my exception"),
                TestUtil.byteBufferFromUtf8String(metadata), TestUtil.byteBufferFromUtf8String(data));
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals(FrameType.ERROR, reusableFrame.getType());
        assertEquals(data, TestUtil.byteToString(reusableFrame.getData()));
        assertEquals(metadata, TestUtil.byteToString(reusableFrame.getMetadata()));
    }

    @Test
    @Theory
    public void shouldFormCorrectlyForRequestN(final int offset) {
        final int n = 128;
        final Frame encodedFrame = Frame.RequestN.from(1, n);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals(FrameType.REQUEST_N, reusableFrame.getType());
        assertEquals(n, Frame.RequestN.requestN(reusableFrame));
        assertEquals(Frame.NULL_BYTEBUFFER, reusableFrame.getData());
        assertEquals(Frame.NULL_BYTEBUFFER, reusableFrame.getMetadata());

        assertEquals("00000010000900000000000100000080",
                ByteBufUtil.hexDump(encodedFrame.getByteBuffer().array(), 0, 16));
    }

    @Test
    @Theory
    public void shouldFormCorrectlyWithoutMetadataForLease(final int offset) {
        final int ttl = (int) TimeUnit.SECONDS.toMillis(8);
        final int numberOfRequests = 16;
        final Frame encodedFrame = Frame.Lease.from(ttl, numberOfRequests, Frame.NULL_BYTEBUFFER);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals(0, reusableFrame.getStreamId());
        assertEquals(FrameType.LEASE, reusableFrame.getType());
        assertEquals(ttl, Frame.Lease.ttl(reusableFrame));
        assertEquals(numberOfRequests, Frame.Lease.numberOfRequests(reusableFrame));
        assertEquals(Frame.NULL_BYTEBUFFER, reusableFrame.getData());
        assertEquals(Frame.NULL_BYTEBUFFER, reusableFrame.getMetadata());

        assertEquals("00000014000200000000000000001f4000000010",
                ByteBufUtil.hexDump(encodedFrame.getByteBuffer().array(), 0, 20));
    }

    @Test
    @Theory
    public void shouldFormCorrectlyWithMetadataForLease(final int offset) {
        final int ttl = (int) TimeUnit.SECONDS.toMillis(8);
        final int numberOfRequests = 16;
        final ByteBuffer leaseMetadata = TestUtil.byteBufferFromUtf8String("lease metadata");

        final Frame encodedFrame = Frame.Lease.from(ttl, numberOfRequests, leaseMetadata);
        TestUtil.copyFrame(reusableMutableDirectBuffer, offset, encodedFrame);
        reusableFrame.wrap(reusableMutableDirectBuffer, offset);

        assertEquals(0, reusableFrame.getStreamId());
        assertEquals(FrameType.LEASE, reusableFrame.getType());
        assertEquals(ttl, Frame.Lease.ttl(reusableFrame));
        assertEquals(numberOfRequests, Frame.Lease.numberOfRequests(reusableFrame));
        assertEquals(Frame.NULL_BYTEBUFFER, reusableFrame.getData());
        assertEquals("lease metadata", TestUtil.byteToString(reusableFrame.getMetadata()));
    }
}