io.moquette.parser.netty.PublishDecoderTest.java Source code

Java tutorial

Introduction

Here is the source code for io.moquette.parser.netty.PublishDecoderTest.java

Source

/*
 * Copyright (c) 2012-2015 The original author or authors
 * ------------------------------------------------------
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Apache License v2.0 which accompanies this distribution.
 *
 * The Eclipse Public License is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * The Apache License v2.0 is available at
 * http://www.opensource.org/licenses/apache2.0.php
 *
 * You may elect to redistribute this code under either of these licenses.
 */
package io.moquette.parser.netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.CorruptedFrameException;
import io.netty.util.AttributeMap;
import io.netty.util.DefaultAttributeMap;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import io.moquette.parser.proto.messages.AbstractMessage;
import io.moquette.parser.proto.messages.PublishMessage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import org.junit.Before;
import org.junit.Test;

/**
 *
 * @author andrea
 */
public class PublishDecoderTest {
    ByteBuf m_buff;
    PublishDecoder m_msgdec;
    List<Object> m_results;
    AttributeMap m_attrMap;

    private static final int MESSAGE_ID = 123;

    @Before
    public void setUp() {
        m_msgdec = new PublishDecoder();
        m_results = new ArrayList<>();
        m_attrMap = new DefaultAttributeMap();
    }

    @Test
    public void testHeader() throws Exception {
        m_buff = Unpooled.buffer(14);
        initHeader(m_buff);

        //Exercise
        m_msgdec.decode(m_attrMap, m_buff, m_results);

        assertFalse(m_results.isEmpty());
        PublishMessage message = (PublishMessage) m_results.get(0);
        assertNotNull(message);
        assertEquals("Fake Topic", message.getTopicName());
        assertNull(message.getMessageID());
        assertEquals(AbstractMessage.PUBLISH, message.getMessageType());
    }

    @Test
    public void testHeaderWithMessageID() throws Exception {
        m_buff = Unpooled.buffer(14);
        initHeaderWithMessageID(m_buff, MESSAGE_ID);

        //Exercise
        m_msgdec.decode(m_attrMap, m_buff, m_results);

        assertFalse(m_results.isEmpty());
        PublishMessage message = (PublishMessage) m_results.get(0);
        assertNotNull(message);
        assertEquals("Fake Topic", message.getTopicName());
        assertEquals(MESSAGE_ID, (int) message.getMessageID());
    }

    @Test
    public void testHeaderWithMessageID_Payload() throws Exception {
        m_buff = Unpooled.buffer(14);
        //        byte[] payload = new byte[]{0x0A, 0x0B, 0x0C};
        ByteBuffer payload = ByteBuffer.allocate(3).put(new byte[] { 0x0A, 0x0B, 0x0C });
        initHeaderWithMessageID_Payload(m_buff, MESSAGE_ID, payload);

        //Exercise
        m_msgdec.decode(m_attrMap, m_buff, m_results);

        assertFalse(m_results.isEmpty());
        PublishMessage message = (PublishMessage) m_results.get(0);
        assertNotNull(message);
        assertEquals("Fake Topic", message.getTopicName());
        assertEquals(MESSAGE_ID, (int) message.getMessageID());
        //        TestUtils.verifyEquals(payload, message.getPayload());
        assertEquals(payload, message.getPayload());
    }

    @Test(expected = CorruptedFrameException.class)
    public void testDup0WithQoS0_3_1_1() throws Exception {
        m_buff = preparePubclishWithQosFlags((byte) 0x08);

        //Exercise
        m_msgdec.decode(m_attrMap, m_buff, m_results);
    }

    @Test(expected = CorruptedFrameException.class)
    public void testReservedQoS3_3_1_1() throws Exception {
        m_buff = preparePubclishWithQosFlags((byte) 0x0E);

        //Exercise
        m_msgdec.decode(m_attrMap, m_buff, m_results);
    }

    @Test(expected = CorruptedFrameException.class)
    public void testTopicWithWildCards() throws Exception {
        byte[] overallMessage = new byte[] { 0x30, 0x17, //fixed header, 25 byte length
                0x00, 0x06, 0x2f, 0x74, 0x6f, 0x70, 0x2B /*+*/, 0x23 /*#*/, //[/top+#] string 2 len + 6 content
                0x54, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x79, // [Test my payload] encoding
                0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64 };
        m_buff = Unpooled.buffer(overallMessage.length);
        m_buff.writeBytes(overallMessage);

        //Exercise
        m_msgdec.decode(m_attrMap, m_buff, m_results);
    }

    @Test
    public void testBugOnRealCase() throws Exception {
        byte[] overallMessage = new byte[] { 0x30, 0x17, //fixed header, 25 byte length
                0x00, 0x06, 0x2f, 0x74, 0x6f, 0x70, 0x69, 0x63, //[/topic] string 2 len + 6 content
                0x54, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x79, // [Test my payload] encoding
                0x20, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64 };
        m_buff = Unpooled.buffer(overallMessage.length);
        m_buff.writeBytes(overallMessage);

        //Exercise
        m_msgdec.decode(m_attrMap, m_buff, m_results);

        assertFalse(m_results.isEmpty());
        PublishMessage message = (PublishMessage) m_results.get(0);
        assertNotNull(message);
    }

    @Test
    public void testDecodeBigContent() throws Exception {
        int size = 129;
        ByteBuf payload = TestUtils.generateRandomPayload(size);

        ByteBuf firstPublish = generatePublishQoS0(payload);
        ByteBuf secondPublish = generatePublishQoS0(TestUtils.generateRandomPayload(size));

        ByteBuf doubleMessageBuf = Unpooled.buffer(size * 2);
        doubleMessageBuf.writeBytes(firstPublish).writeBytes(secondPublish);

        //Exercise
        m_msgdec.decode(m_attrMap, doubleMessageBuf, m_results);

        assertFalse(m_results.isEmpty());
        PublishMessage message = (PublishMessage) m_results.get(0);
        assertNotNull(message);
        m_results.clear();

        m_msgdec.decode(m_attrMap, doubleMessageBuf, m_results);

        assertFalse(m_results.isEmpty());
        message = (PublishMessage) m_results.get(0);
        assertNotNull(message);
    }

    @Test
    public void testBadClaimMoreData() throws Exception {
        byte[] rawMessage = new byte[] { 0x30, 0x17, 0x00, 0x06, 0x2f, (byte) 0x74, 0x6f, (byte) 0x70, 0x69, 0x63,
                0x54, 0x65, (byte) 0x73, 0x74, 0x20, 0x6d, (byte) 0x79, 0x20, (byte) 0x70, 0x61, (byte) 0x79, 0x6c,
                0x6f, 0x61, 0x64 };

        ByteBuf msgBuf = Unpooled.buffer(25);
        msgBuf.writeBytes(rawMessage);
        msgBuf.readByte(); //to simulate the reading of messageType done by MQTTDecoder dispatcher

        //Exercise
        m_msgdec.decode(m_attrMap, msgBuf, m_results);

        assertFalse(m_results.isEmpty());
        PublishMessage message = (PublishMessage) m_results.get(0);
        assertNotNull(message);
        assertEquals("/topic", message.getTopicName());
        //        assertEquals("Test my payload", new String(message.getPayload()));
        Buffer expectedPayload = ByteBuffer.allocate(15).put("Test my payload".getBytes()).flip();
        assertEquals(expectedPayload, message.getPayload());
    }

    /*
     * Check topic is at least one char [MQTT-4.7.3-1]
     * */
    @Test(expected = CorruptedFrameException.class)
    public void testMinimumTopicLength() throws Exception {
        ByteBuf packet = packetWithTopic("");

        //Exercise
        m_msgdec.decode(m_attrMap, packet, m_results);
    }

    private void initHeader(ByteBuf buff) throws IllegalAccessException {
        ByteBuf tmp = Unpooled.buffer(4).writeBytes(Utils.encodeString("Fake Topic"));
        buff.clear().writeByte(AbstractMessage.PUBLISH << 4)
                .writeBytes(Utils.encodeRemainingLength(tmp.readableBytes()));
        //topic name
        buff.writeBytes(tmp);
    }

    private ByteBuf packetWithTopic(String topicName) throws IllegalAccessException {
        ByteBuf buff = Unpooled.buffer(14);
        ByteBuf topicBuff = Unpooled.buffer(4).writeBytes(Utils.encodeString(topicName));
        buff.clear().writeByte(AbstractMessage.PUBLISH << 4)
                .writeBytes(Utils.encodeRemainingLength(topicBuff.readableBytes()));
        //topic name
        buff.writeBytes(topicBuff);
        return buff;
    }

    private void initHeaderWithMessageID(ByteBuf buff, int messageID) throws IllegalAccessException {
        ByteBuf tmp = Unpooled.buffer(4).writeBytes(Utils.encodeString("Fake Topic"));
        tmp.writeShort(messageID);
        buff.clear().writeByte(AbstractMessage.PUBLISH << 4 | 0x02) //set Qos to 1
                .writeBytes(Utils.encodeRemainingLength(tmp.readableBytes()));
        //topic name
        buff.writeBytes(tmp);
    }

    private void initHeaderWithMessageID_Payload(ByteBuf buff, int messageID, byte[] payload)
            throws IllegalAccessException {
        ByteBuf tmp = Unpooled.buffer(4).writeBytes(Utils.encodeString("Fake Topic"));
        tmp.writeShort(messageID);
        tmp.writeBytes(payload);
        buff.clear().writeByte(AbstractMessage.PUBLISH << 4 | 0x02) //set Qos to 1
                .writeBytes(Utils.encodeRemainingLength(tmp.readableBytes()));
        //topic name
        buff.writeBytes(tmp);
    }

    private void initHeaderWithMessageID_Payload(ByteBuf buff, int messageID, ByteBuffer payload)
            throws IllegalAccessException {
        ByteBuf tmp = Unpooled.buffer(4).writeBytes(Utils.encodeString("Fake Topic"));
        tmp.writeShort(messageID);
        tmp.writeBytes(payload);
        buff.clear().writeByte(AbstractMessage.PUBLISH << 4 | 0x02) //set Qos to 1
                .writeBytes(Utils.encodeRemainingLength(tmp.readableBytes()));
        //topic name
        buff.writeBytes(tmp);
    }

    private ByteBuf generatePublishQoS0(ByteBuf payload) throws IllegalAccessException {
        int size = payload.capacity();
        ByteBuf messageBody = Unpooled.buffer(size);
        messageBody.writeBytes(Utils.encodeString("/topic"));

        //ONLY for QoS > 1 Utils.writeWord(messageBody, messageID);
        messageBody.writeBytes(payload);

        ByteBuf completeMsg = Unpooled.buffer(size);
        completeMsg.clear().writeByte(AbstractMessage.PUBLISH << 4 | 0x00) //set Qos to 0
                .writeBytes(Utils.encodeRemainingLength(messageBody.readableBytes()));
        completeMsg.writeBytes(messageBody);

        return completeMsg;
    }

    private ByteBuf preparePubclishWithQosFlags(byte flags) {
        ByteBuf buff = Unpooled.buffer(14);
        ByteBuffer payload = ByteBuffer.allocate(3).put(new byte[] { 0x0A, 0x0B, 0x0C });
        ByteBuf tmp = Unpooled.buffer(4).writeBytes(Utils.encodeString("Fake Topic"));
        tmp.writeShort(MESSAGE_ID);
        tmp.writeBytes(payload);
        buff.clear().writeByte(AbstractMessage.PUBLISH << 4 | flags) //set DUP=1 Qos to 11 => b1110
                .writeBytes(Utils.encodeRemainingLength(tmp.readableBytes()));
        //topic name
        buff.writeBytes(tmp);

        return buff;
    }
}