com.linecorp.armeria.common.thrift.text.TTextProtocolTest.java Source code

Java tutorial

Introduction

Here is the source code for com.linecorp.armeria.common.thrift.text.TTextProtocolTest.java

Source

// =================================================================================================
// Copyright 2011 Twitter, Inc.
// -------------------------------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this work except in compliance with the License.
// You may obtain a copy of the License in the LICENSE file, or 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 com.linecorp.armeria.common.thrift.text;

import static net.javacrumbs.jsonunit.JsonAssert.assertJsonEquals;
import static org.junit.Assert.assertEquals;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.EnumSet;

import org.apache.commons.codec.binary.Base64;
import org.apache.thrift.TApplicationException;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TMessage;
import org.apache.thrift.protocol.TMessageType;
import org.apache.thrift.transport.TIOStreamTransport;
import org.junit.Before;
import org.junit.Test;

import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.Resources;

import com.linecorp.armeria.common.thrift.text.RpcDebugService.doDebug_args;
import com.linecorp.armeria.common.thrift.text.RpcDebugService.doDebug_result;

/**
 * Tests the TTextProtocol.
 *
 * <p>TODO(Alex Roetter): add more tests, especially ones that verify
 * that we generate ParseErrors for invalid input
 *
 * @author Alex Roetter
 */
public class TTextProtocolTest {

    private String fileContents;
    private Base64 base64Encoder;

    /**
     * Load a file containing a serialized thrift message in from disk.
     */
    @Before
    public void setUp() throws IOException {
        fileContents = Resources.toString(Resources.getResource(getClass(),
                "/com/linecorp/armeria/common/thrift/text/TTextProtocol_TestData.txt"), Charsets.UTF_8);

        base64Encoder = new Base64();
    }

    /**
     * Read in (deserialize) a thrift message in TTextProtocol format
     * from a file on disk, then serialize it back out to a string.
     * Finally, deserialize that string and compare to the original
     * message.
     */
    @Test
    public void tTextProtocolReadWriteTest() throws Exception {
        // Deserialize the file contents into a thrift message.
        ByteArrayInputStream bais1 = new ByteArrayInputStream(fileContents.getBytes());

        TTextProtocolTestMsg msg1 = new TTextProtocolTestMsg();
        msg1.read(new TTextProtocol(new TIOStreamTransport(bais1)));

        assertEquals(testMsg(), msg1);

        // Serialize that thrift message out to a byte array
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        msg1.write(new TTextProtocol(new TIOStreamTransport(baos)));
        byte[] bytes = baos.toByteArray();

        // Deserialize that string back to a thrift message.
        ByteArrayInputStream bais2 = new ByteArrayInputStream(bytes);
        TTextProtocolTestMsg msg2 = new TTextProtocolTestMsg();
        msg2.read(new TTextProtocol(new TIOStreamTransport(bais2)));

        assertEquals(msg1, msg2);
    }

    private TTextProtocolTestMsg testMsg() {

        return new TTextProtocolTestMsg().setA(12345L).setB(5).setC(sub(1, 10))
                .setD(ImmutableList.of(7, 8, 9, 10, 11))
                .setE(ImmutableList.of(sub(2, 100), sub(3, 200), sub(4, 300))).setF(true).setG((byte) 12)
                .setH(ImmutableMap.of(1, 2L, 3, 4L, 5, 6L))
                .setJ(ImmutableMap.of((short) 1, ImmutableList.of(true, true, false, true), (short) 5,
                        ImmutableList.of(false)))
                .setK(ImmutableSet.of(true, false, false, false, true))
                .setL(base64Encoder.decode("SGVsbG8gV29ybGQ=")).setM("hello \"spherical\" world!").setN((short) 678)
                .setP(Letter.CHARLIE).setQ(EnumSet.allOf(Letter.class)).setR(ImmutableMap.of(sub(1, 2), 100L))
                .setS(ImmutableMap.of(ImmutableMap.of(ImmutableMap.of(200L, 400L), 300L), 100L))
                .setT(ImmutableList.of(Letter.ALPHA, Letter.ALPHA, Letter.CHARLIE, Letter.ALPHA, Letter.CHARLIE,
                        Letter.ECHO))
                .setU(ImmutableMap.of("foo", Letter.ALPHA, "bar", Letter.DELTA)).setV(Letter.BETA)
                .setW(TestUnion.f2(4))
                .setX(ImmutableList.of(TestUnion.f2(5), TestUnion.f1(base64Encoder.decode("SGVsbG8gV29ybGQ="))))
                .setY(Letter.ALPHA);

    }

    private static Sub sub(int s, int x) {
        return new Sub(s, new SubSub(x));
    }

    @Test
    public void rpcCall() throws Exception {
        String request = "{\n" + "  \"method\" : \"doDebug\",\n" + "  \"type\" : \"CALL\",\n" + "  \"seqid\" : 1,\n"
                + "  \"args\" : {\n" + "    \"methodArg1\" : \"foo1\",\n" + "    \"methodArg2\" : 200,\n"
                + "    \"details\" : {\n" + "      \"detailsArg1\" : \"foo2\",\n" + "      \"detailsArg2\" : 100\n"
                + "    }\n" + "  }\n" + '}';

        TTextProtocol prot = new TTextProtocol(
                new TIOStreamTransport(new ByteArrayInputStream(request.getBytes())));
        TMessage header = prot.readMessageBegin();
        doDebug_args args = new RpcDebugService.Processor.doDebug().getEmptyArgsInstance();
        args.read(prot);
        prot.readMessageEnd();

        assertEquals("doDebug", header.name);
        assertEquals(TMessageType.CALL, header.type);
        assertEquals(1, header.seqid);

        assertEquals("foo1", args.getMethodArg1());
        assertEquals(200, args.getMethodArg2());
        assertEquals("foo2", args.getDetails().getDetailsArg1());
        assertEquals(100, args.getDetails().getDetailsArg2());

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        prot = new TTextProtocol(new TIOStreamTransport(outputStream));
        prot.writeMessageBegin(header);
        args.write(prot);
        prot.writeMessageEnd();

        assertJsonEquals(request, new String(outputStream.toByteArray(), StandardCharsets.UTF_8));
    }

    @Test
    public void rpcCall_noSeqId() throws Exception {
        String request = "{\n" + "  \"method\" : \"doDebug\",\n" + "  \"type\" : \"CALL\",\n" + "  \"args\" : {\n"
                + "    \"methodArg1\" : \"foo1\",\n" + "    \"methodArg2\" : 200,\n" + "    \"details\" : {\n"
                + "      \"detailsArg1\" : \"foo2\",\n" + "      \"detailsArg2\" : 100\n" + "    }\n" + "  }\n"
                + '}';

        TTextProtocol prot = new TTextProtocol(
                new TIOStreamTransport(new ByteArrayInputStream(request.getBytes())));
        TMessage header = prot.readMessageBegin();
        doDebug_args args = new RpcDebugService.Processor.doDebug().getEmptyArgsInstance();
        args.read(prot);
        prot.readMessageEnd();

        assertEquals("doDebug", header.name);
        assertEquals(TMessageType.CALL, header.type);
        assertEquals(0, header.seqid);
    }

    @Test
    public void rpcCall_oneWay() throws Exception {
        String request = "{\n" + "  \"method\" : \"doDebug\",\n" + "  \"type\" : \"ONEWAY\",\n"
                + "  \"seqid\" : 1,\n" + "  \"args\" : {\n" + "    \"methodArg1\" : \"foo1\",\n"
                + "    \"methodArg2\" : 200,\n" + "    \"details\" : {\n" + "      \"detailsArg1\" : \"foo2\",\n"
                + "      \"detailsArg2\" : 100\n" + "    }\n" + "  }\n" + '}';

        TTextProtocol prot = new TTextProtocol(
                new TIOStreamTransport(new ByteArrayInputStream(request.getBytes())));
        TMessage header = prot.readMessageBegin();
        doDebug_args args = new RpcDebugService.Processor.doDebug().getEmptyArgsInstance();
        args.read(prot);
        prot.readMessageEnd();

        assertEquals("doDebug", header.name);
        assertEquals(TMessageType.ONEWAY, header.type);
        assertEquals(1, header.seqid);

        assertEquals("foo1", args.getMethodArg1());
        assertEquals(200, args.getMethodArg2());
        assertEquals("foo2", args.getDetails().getDetailsArg1());
        assertEquals(100, args.getDetails().getDetailsArg2());

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        prot = new TTextProtocol(new TIOStreamTransport(outputStream));
        prot.writeMessageBegin(header);
        args.write(prot);
        prot.writeMessageEnd();

        assertJsonEquals(request, new String(outputStream.toByteArray(), StandardCharsets.UTF_8));
    }

    @Test
    public void rpcReply() throws Exception {
        String request = "{\n" + "  \"method\" : \"doDebug\",\n" + "  \"type\" : \"REPLY\",\n"
                + "  \"seqid\" : 100,\n" + "  \"args\" : {\n" + "    \"success\" : {\n"
                + "      \"response\" : \"Nice response\"\n" + "    }\n" + "  }\n" + '}';

        TTextProtocol prot = new TTextProtocol(
                new TIOStreamTransport(new ByteArrayInputStream(request.getBytes())));
        TMessage header = prot.readMessageBegin();
        doDebug_result result = new doDebug_result();
        result.read(prot);
        prot.readMessageEnd();

        assertEquals("doDebug", header.name);
        assertEquals(TMessageType.REPLY, header.type);
        assertEquals(100, header.seqid);

        assertEquals("Nice response", result.getSuccess().getResponse());

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        prot = new TTextProtocol(new TIOStreamTransport(outputStream));
        prot.writeMessageBegin(header);
        result.write(prot);
        prot.writeMessageEnd();

        assertJsonEquals(request, new String(outputStream.toByteArray(), StandardCharsets.UTF_8));
    }

    @Test
    public void rpcException() throws Exception {
        String request = "{\n" + "  \"method\" : \"doDebug\",\n" + "  \"type\" : \"EXCEPTION\",\n"
                + "  \"seqid\" : 101,\n" + "  \"args\" : {\n" + "    \"e\" : {\n"
                + "      \"reason\" : \"Bad rpc\"\n" + "    }\n" + "  }\n" + '}';

        TTextProtocol prot = new TTextProtocol(
                new TIOStreamTransport(new ByteArrayInputStream(request.getBytes())));
        TMessage header = prot.readMessageBegin();
        doDebug_result result = new doDebug_result();
        result.read(prot);
        prot.readMessageEnd();

        assertEquals("doDebug", header.name);
        assertEquals(TMessageType.EXCEPTION, header.type);
        assertEquals(101, header.seqid);

        assertEquals("Bad rpc", result.getE().getReason());

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        prot = new TTextProtocol(new TIOStreamTransport(outputStream));
        prot.writeMessageBegin(header);
        result.write(prot);
        prot.writeMessageEnd();

        assertJsonEquals(request, new String(outputStream.toByteArray(), StandardCharsets.UTF_8));
    }

    @Test
    public void rpcTApplicationException() throws Exception {
        String request = "{\n" + "  \"method\" : \"doDebug\",\n" + "  \"type\" : \"EXCEPTION\",\n"
                + "  \"seqid\" : 101,\n" + "  \"args\" : {\n" + "    \"type\" : 4,\n"
                + "    \"message\" : \"bad_seq_id\"\n" + "    }\n" + "  }\n" + '}';

        TTextProtocol prot = new TTextProtocol(
                new TIOStreamTransport(new ByteArrayInputStream(request.getBytes())));
        TMessage header = prot.readMessageBegin();
        TApplicationException result = TApplicationException.read(prot);
        prot.readMessageEnd();

        assertEquals("doDebug", header.name);
        assertEquals(TMessageType.EXCEPTION, header.type);
        assertEquals(101, header.seqid);

        assertEquals(TApplicationException.BAD_SEQUENCE_ID, result.getType());

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        prot = new TTextProtocol(new TIOStreamTransport(outputStream));
        prot.writeMessageBegin(header);
        new TApplicationException(TApplicationException.BAD_SEQUENCE_ID, "bad_seq_id").write(prot);
        prot.writeMessageEnd();

        assertJsonEquals(request, new String(outputStream.toByteArray(), StandardCharsets.UTF_8));
    }

    @Test(expected = TException.class)
    public void rpcNoMethod() throws Exception {
        String request = "{\n" + "  \"type\" : \"CALL\",\n" + "  \"args\" : {\n"
                + "    \"methodArg1\" : \"foo1\",\n" + "    \"methodArg2\" : 200,\n" + "    \"details\" : {\n"
                + "      \"detailsArg1\" : \"foo2\",\n" + "      \"detailsArg2\" : 100\n" + "    }\n" + "  }\n"
                + '}';
        TTextProtocol prot = new TTextProtocol(
                new TIOStreamTransport(new ByteArrayInputStream(request.getBytes())));
        prot.readMessageBegin();
    }

    @Test(expected = TException.class)
    public void rpcNoType() throws Exception {
        String request = "{\n" + "  \"method\" : \"doDebug\",\n" + "  \"args\" : {\n"
                + "    \"methodArg1\" : \"foo1\",\n" + "    \"methodArg2\" : 200,\n" + "    \"details\" : {\n"
                + "      \"detailsArg1\" : \"foo2\",\n" + "      \"detailsArg2\" : 100\n" + "    }\n" + "  }\n"
                + '}';
        TTextProtocol prot = new TTextProtocol(
                new TIOStreamTransport(new ByteArrayInputStream(request.getBytes())));
        prot.readMessageBegin();
    }

    @Test(expected = TException.class)
    public void noRpcArgs() throws Exception {
        String request = "{\n" + "  \"method\" : \"doDebug\"\n" + "  \"type\" : \"CALL\",\n" + '}';
        TTextProtocol prot = new TTextProtocol(
                new TIOStreamTransport(new ByteArrayInputStream(request.getBytes())));
        prot.readMessageBegin();
    }

    @Test(expected = TException.class)
    public void rpcArgsNotObject() throws Exception {
        String request = "{\n" + "  \"method\" : \"doDebug\",\n" + "  \"args\" : 100\n" + '}';
        TTextProtocol prot = new TTextProtocol(
                new TIOStreamTransport(new ByteArrayInputStream(request.getBytes())));
        prot.readMessageBegin();
    }
}