changeset 2296:7596994808a2

Fix decoding of Request messages. Reviewed-by: neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-May/018803.html
author Severin Gehwolf <sgehwolf@redhat.com>
date Thu, 12 May 2016 15:46:30 +0200
parents 5d4c3090df2d
children 524aeb3ae995
files agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelRequestDecoder.java agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelRequestDecoderTest.java agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/JsonResponseParserTest.java agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/RequestDecoderTest.java agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/ResponseParserTest.java
diffstat 5 files changed, 787 insertions(+), 395 deletions(-) [+]
line wrap: on
line diff
--- a/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelRequestDecoder.java	Thu May 12 11:17:00 2016 -0400
+++ b/agent/command-server/src/main/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelRequestDecoder.java	Thu May 12 15:46:30 2016 +0200
@@ -91,7 +91,7 @@
 class CommandChannelRequestDecoder extends ByteToMessageDecoder {
     
     private static final Logger logger = LoggingUtils.getLogger(CommandChannelRequestDecoder.class);
-
+    
     @Override
     protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception {
         logger.log(Level.FINEST, "Command channel server: decoding Request object");
@@ -104,19 +104,20 @@
         if (typeAsString == null) {
             throw new InvalidMessageException("Could not decode message: " + ByteBufUtil.hexDump(buf));
         }
-        // clean up resources
-        buf.readerIndex(buf.readerIndex() + stringDecCtx.getBytesRead());
-        buf.discardReadBytes();
         // Netty javadoc tells us it's safe to downcast to more concrete type.
         InetSocketAddress addr = (InetSocketAddress)ctx.channel().remoteAddress();
         Request request = new Request(RequestType.valueOf(typeAsString), addr);
-        ParameterDecodingContext paramCtx = DecodingHelper.decodeParameters(buf);
+        int remainingLength = buf.readableBytes() - stringDecCtx.getBytesRead();
+        ByteBuf adjustedBuffer = buf.slice(stringDecCtx.getBytesRead(), remainingLength);
+        ParameterDecodingContext paramCtx = DecodingHelper.decodeParameters(adjustedBuffer);
         if (paramCtx.getState() != ParameterDecodingState.ALL_PARAMETERS_READ) {
             // insufficient data
             return;
         }
-        // clean up resources
-        buf.readerIndex(buf.readerIndex() + paramCtx.getBytesRead());
+        // clean up resources from the request type + parameters
+        int totalBytesRead = stringDecCtx.getBytesRead() +
+                                paramCtx.getBytesRead();
+        buf.readerIndex(buf.readerIndex() + totalBytesRead);
         buf.discardReadBytes();
         for (Entry<String, String> kv: paramCtx.getValues().entrySet()) {
             request.setParameter(kv.getKey(), kv.getValue());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/CommandChannelRequestDecoderTest.java	Thu May 12 15:46:30 2016 +0200
@@ -0,0 +1,580 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.agent.command.server.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.command.Message;
+import com.redhat.thermostat.common.command.Messages;
+import com.redhat.thermostat.common.command.Request;
+import com.redhat.thermostat.common.command.Request.RequestType;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+
+public class CommandChannelRequestDecoderTest {
+    
+    private static final String LONG_PARAM_VALUE = "RULE count sleep method invocations\n" +
+            "CLASS com.redhat.thermostat.byteman.test.InfiniteLoop\n" +
+            "METHOD sleep\n" +
+            "AT ENTRY\n" +
+            "IF true\n" +
+            "DO\n" +
+            "incrementCounter(\"sleep-counter\")\n" +
+            "ENDRULE\n" +
+            "\n" +
+            "RULE send sleep method invocations to thermostat\n" +
+            "CLASS com.redhat.thermostat.byteman.test.InfiniteLoop\n" +
+            "METHOD sleep\n" +
+            "HELPER org.jboss.byteman.thermostat.helper.ThermostatHelper\n" +
+            "AT ENTRY\n" +
+            "BIND counterValue: int = readCounter(\"sleep-counter\")\n" +
+            "IF counterValue % 10 == 0\n" +
+            "DO\n" +
+            "send(\"com.redhat.thermostat.byteman.test.InfiniteLoop\",  \"method sleep() count\", counterValue);\n" +
+            "ENDRULE\n";
+    
+    /*
+     * This is serialized format for
+     * req = new Request(RequestType.RESPONSE_EXPECTED, blah);
+     * req.setParameter("param1", "value1");
+     * req.setParameter("param2", "value2");
+     */
+    private static final byte[] ENCODED_REQUEST_WITH_PARAMS = new byte[] {
+        0x00, 0x00, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45,
+        0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, 0x00, 0x00, 0x00,
+        0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x70, 0x61, 0x72,
+        0x61, 0x6d, 0x31, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x00, 0x00, 0x00,
+        0x06, 0x00, 0x00, 0x00, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x32, 0x76,
+        0x61, 0x6c, 0x75, 0x65, 0x32
+    };
+    
+    /*
+     * This is serialized format for:
+     * 
+     * Request req = new Request(RequestType.RESPONSE_EXPECTED, blah);
+     * req.setReceiver("com.redhat.thermostat.vm.byteman.agent.internal.BytemanRequestReceiver");
+     * req.setParameter("action-name", "vm-byteman-instrument");
+     * req.setParameter("vm-id", "f5b4cc44-06f2-4847-97d3-b5b0b198f843");
+     * req.setParameter("byteman-action", Integer.toString(0));
+     * req.setParameter("listen-port", Integer.toString(listenPort));
+     * req.setParameter("auth-token", "/UFDv9PT3nLMW1lEJUyTxfIHfU8bRxcAw4IdVYL7JzHROruzNvIpuvqrLUN01f0hGIGMmzc58iylrbpgY1wkUA04YL5WOF66ysfwLWwDA8M2R7khrK0xY6+DLSA1nOUT+ihmvGsrlk51x5aqH7Vvqqj+TDyj8Z3Gl3dMp6KEngtBxxhxO/pI9euQGUiwWGcY7CdTAoTSx2wh8bOsmDUllwOE7978ZhTRsSN0bd57eynDaae23TwInhez5iHOxuWlByjEv4RyDPSc0fASoKwH7IAj7VYMzuj72/c9xLOA54XuyruaMdqi0zlA4v/af7xJ90XVMWdW96EGBGkIlo33fA==");
+     * req.setParameter("client-token", "MdJ08lQ4+4H9asOQaYxV6XDXbICi3njI7JmZ9W8WgN7LW8RIYZ0aCFpaHQIHsG38mOLvZRzLNwI45NG/qoxVu+BA8ekEBpLlHCotxLk+1F7yZonmkEfXq6o4imsVU/8EU36Dh7YRd5qOnerJ7NItrw/kBuVaAlsVL2Bbj7ryvVVE01GgMJlBLQjnjb21eO2yg2w4AKDOggHMwcCAaZl1wW1pKQJAvlT0FYHrwSUJQ51JrZEUJjFxZ38xxYHA0HMffUiDczqkFj08w59G/652JY/hWpoM9uzwZP+tV4sCWXFF5IuBB8PFwaeqgXDwrbxgYMjCgk9nNZuvdsdaV1bGRQ==");
+     * req.setParameter("byteman-rule", LONG_PARAM_VALUE);
+     */
+    private static final byte[] ENCODED_REQUEST_WITH_MANY_PARAMS = new byte[] {
+        0x00, 0x00, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45,
+        0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44,
+        0x00, 0x00, 0x00, 0x08, // 8 parameters, slice A end
+        0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x15, 0x61, 0x63, 0x74, 0x69,
+        0x6f, 0x6e, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x76, 0x6d, 0x2d, 0x62, 0x79,
+        0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2d, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75,
+        0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x58,
+        0x61, 0x75, 0x74, 0x68, 0x2d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2f, 0x55,
+        0x46, 0x44, 0x76, 0x39, 0x50, 0x54, 0x33, 0x6e, 0x4c, 0x4d, 0x57, 0x31,
+        0x6c, 0x45, 0x4a, 0x55, 0x79, 0x54, 0x78, 0x66, 0x49, 0x48, 0x66, 0x55,
+        0x38, 0x62, 0x52, 0x78, 0x63, 0x41, 0x77, 0x34, 0x49, 0x64, 0x56, 0x59,
+        0x4c, 0x37, 0x4a, 0x7a, 0x48, 0x52, 0x4f, 0x72, 0x75, 0x7a, 0x4e, 0x76,
+        0x49, 0x70, 0x75, 0x76, 0x71, 0x72, 0x4c, 0x55, 0x4e, 0x30, 0x31, 0x66,
+        0x30, 0x68, 0x47, 0x49, 0x47, 0x4d, 0x6d, 0x7a, 0x63, 0x35, 0x38, 0x69,
+        0x79, 0x6c, 0x72, 0x62, 0x70, 0x67, 0x59, 0x31, 0x77, 0x6b, 0x55, 0x41,
+        0x30, 0x34, 0x59, 0x4c, 0x35, 0x57, 0x4f, 0x46, 0x36, 0x36, 0x79, 0x73,
+        0x66, 0x77, 0x4c, 0x57, 0x77, 0x44, 0x41, 0x38, 0x4d, 0x32, 0x52, 0x37,
+        0x6b, 0x68, 0x72, 0x4b, 0x30, 0x78, 0x59, 0x36, 0x2b, 0x44, 0x4c, 0x53,
+        0x41, 0x31, 0x6e, 0x4f, 0x55, 0x54, 0x2b, 0x69, 0x68, 0x6d, 0x76, 0x47,
+        0x73, 0x72, 0x6c, 0x6b, 0x35, 0x31, 0x78, 0x35, 0x61, 0x71, 0x48, 0x37,
+        0x56, 0x76, 0x71, 0x71, 0x6a, 0x2b, 0x54, 0x44, 0x79, 0x6a, 0x38, 0x5a,
+        0x33, 0x47, 0x6c, 0x33, 0x64, 0x4d, 0x70, 0x36, 0x4b, 0x45, 0x6e, 0x67,
+        0x74, 0x42, 0x78, 0x78, 0x68, 0x78, 0x4f, 0x2f, 0x70, 0x49, 0x39, 0x65,
+        0x75, 0x51, 0x47, 0x55, 0x69, 0x77, 0x57, 0x47, 0x63, 0x59, 0x37, 0x43,
+        0x64, 0x54, 0x41, 0x6f, 0x54, 0x53, 0x78, 0x32, 0x77, 0x68, 0x38, 0x62,
+        0x4f, 0x73, 0x6d, 0x44, 0x55, 0x6c, 0x6c, 0x77, 0x4f, 0x45, 0x37, 0x39,
+        0x37, 0x38, 0x5a, 0x68, 0x54, 0x52, 0x73, 0x53, 0x4e, 0x30, 0x62, 0x64,
+        0x35, 0x37, 0x65, 0x79, 0x6e, 0x44, 0x61, 0x61, 0x65, 0x32, 0x33, 0x54,
+        0x77, 0x49, 0x6e, 0x68, 0x65, 0x7a, 0x35, 0x69, 0x48, 0x4f, 0x78, 0x75,
+        0x57, 0x6c, 0x42, 0x79, 0x6a, 0x45, 0x76, 0x34, 0x52, 0x79, 0x44, 0x50,
+        0x53, 0x63, 0x30, 0x66, 0x41, 0x53, 0x6f, 0x4b, 0x77, 0x48, 0x37, 0x49,
+        0x41, 0x6a, 0x37, 0x56, 0x59, 0x4d, 0x7a, 0x75, 0x6a, 0x37, 0x32, 0x2f,
+        0x63, 0x39, 0x78, 0x4c, 0x4f, 0x41, 0x35, 0x34, 0x58, 0x75, 0x79, 0x72,
+        0x75, 0x61, 0x4d, 0x64, 0x71, 0x69, 0x30, 0x7a, 0x6c, 0x41, 0x34, 0x76,
+        0x2f, 0x61, 0x66, 0x37, 0x78, 0x4a, 0x39, 0x30, 0x58, 0x56, 0x4d, 0x57,
+        0x64, 0x57, 0x39, 0x36, 0x45, 0x47, 0x42, 0x47, 0x6b, 0x49, 0x6c, 0x6f,
+        0x33, 0x33, 0x66, 0x41, 0x3d, 0x3d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
+        0x00, 0x01, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2d, 0x61, 0x63,
+        0x74, 0x69, 0x6f, 0x6e, 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x02,
+        0x1a, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2d, 0x72, 0x75, 0x6c,
+        0x65, 0x52, 0x55, 0x4c, 0x45, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20,
+        0x73, 0x6c, 0x65, 0x65, 0x70, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,
+        0x20, 0x69, 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+        0x0a, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x72,
+        0x65, 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f,
+        0x73, 0x74, 0x61, 0x74, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e,
+        0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69,
+        0x74, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x0a, 0x4d, 0x45, 0x54, 0x48, 0x4f,
+        0x44, 0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x0a, 0x41, 0x54, 0x20, 0x45,
+        0x4e, 0x54, 0x52, 0x59, 0x0a, 0x49, 0x46, 0x20, 0x74, 0x72, 0x75, 0x65,
+        0x0a, 0x44, 0x4f, 0x0a, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e,
+        0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x28, 0x22, 0x73, 0x6c,
+        0x65, 0x65, 0x70, 0x2d, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22,
+        0x29, 0x0a, 0x45, 0x4e, 0x44, 0x52, 0x55, 0x4c, 0x45, 0x0a, 0x0a, 0x52,
+        0x55, 0x4c, 0x45, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x73, 0x6c, 0x65,
+        0x65, 0x70, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x69, 0x6e,
+        0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f,
+        0x20, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x0a,
+        0x43, 0x4c, 0x41, 0x53, 0x53, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x65,
+        0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f, 0x73,
+        0x74, 0x61, 0x74, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2e,
+        0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x74,
+        0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x0a, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, // slice B end
+        0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x0a, 0x48, 0x45, 0x4c, 0x50, 0x45,
+        0x52, 0x20, 0x6f, 0x72, 0x67, 0x2e, 0x6a, 0x62, 0x6f, 0x73, 0x73, 0x2e,
+        0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2e, 0x74, 0x68, 0x65, 0x72,
+        0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x2e, 0x68, 0x65, 0x6c, 0x70, 0x65,
+        0x72, 0x2e, 0x54, 0x68, 0x65, 0x72, 0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74,
+        0x48, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x0a, 0x41, 0x54, 0x20, 0x45, 0x4e,
+        0x54, 0x52, 0x59, 0x0a, 0x42, 0x49, 0x4e, 0x44, 0x20, 0x63, 0x6f, 0x75,
+        0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x20, 0x69,
+        0x6e, 0x74, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75,
+        0x6e, 0x74, 0x65, 0x72, 0x28, 0x22, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x2d,
+        0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x29, 0x0a, 0x49, 0x46,
+        0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75,
+        0x65, 0x20, 0x25, 0x20, 0x31, 0x30, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x0a,
+        0x44, 0x4f, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x28, 0x22, 0x63, 0x6f, 0x6d,
+        0x2e, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72,
+        0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d,
+        0x61, 0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x66, 0x69,
+        0x6e, 0x69, 0x74, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x22, 0x2c, 0x20, 0x20,
+        0x22, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x73, 0x6c, 0x65, 0x65,
+        0x70, 0x28, 0x29, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2c, 0x20,
+        0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65,
+        0x29, 0x3b, 0x0a, 0x45, 0x4e, 0x44, 0x52, 0x55, 0x4c, 0x45, 0x0a, 0x00,
+        0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x58, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+        0x74, 0x2d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x4d, 0x64, 0x4a, 0x30, 0x38,
+        0x6c, 0x51, 0x34, 0x2b, 0x34, 0x48, 0x39, 0x61, 0x73, 0x4f, 0x51, 0x61,
+        0x59, 0x78, 0x56, 0x36, 0x58, 0x44, 0x58, 0x62, 0x49, 0x43, 0x69, 0x33,
+        0x6e, 0x6a, 0x49, 0x37, 0x4a, 0x6d, 0x5a, 0x39, 0x57, 0x38, 0x57, 0x67,
+        0x4e, 0x37, 0x4c, 0x57, 0x38, 0x52, 0x49, 0x59, 0x5a, 0x30, 0x61, 0x43,
+        0x46, 0x70, 0x61, 0x48, 0x51, 0x49, 0x48, 0x73, 0x47, 0x33, 0x38, 0x6d,
+        0x4f, 0x4c, 0x76, 0x5a, 0x52, 0x7a, 0x4c, 0x4e, 0x77, 0x49, 0x34, 0x35,
+        0x4e, 0x47, 0x2f, 0x71, 0x6f, 0x78, 0x56, 0x75, 0x2b, 0x42, 0x41, 0x38,
+        0x65, 0x6b, 0x45, 0x42, 0x70, 0x4c, 0x6c, 0x48, 0x43, 0x6f, 0x74, 0x78,
+        0x4c, 0x6b, 0x2b, 0x31, 0x46, 0x37, 0x79, 0x5a, 0x6f, 0x6e, 0x6d, 0x6b,
+        0x45, 0x66, 0x58, 0x71, 0x36, 0x6f, 0x34, 0x69, 0x6d, 0x73, 0x56, 0x55,
+        0x2f, 0x38, 0x45, 0x55, 0x33, 0x36, 0x44, 0x68, 0x37, 0x59, 0x52, 0x64,
+        0x35, 0x71, 0x4f, 0x6e, 0x65, 0x72, 0x4a, 0x37, 0x4e, 0x49, 0x74, 0x72,
+        0x77, 0x2f, 0x6b, 0x42, 0x75, 0x56, 0x61, 0x41, 0x6c, 0x73, 0x56, 0x4c,
+        0x32, 0x42, 0x62, 0x6a, 0x37, 0x72, 0x79, 0x76, 0x56, 0x56, 0x45, 0x30,
+        0x31, 0x47, 0x67, 0x4d, 0x4a, 0x6c, 0x42, 0x4c, 0x51, 0x6a, 0x6e, 0x6a,
+        0x62, 0x32, 0x31, 0x65, 0x4f, 0x32, 0x79, 0x67, 0x32, 0x77, 0x34, 0x41,
+        0x4b, 0x44, 0x4f, 0x67, 0x67, 0x48, 0x4d, 0x77, 0x63, 0x43, 0x41, 0x61,
+        0x5a, 0x6c, 0x31, 0x77, 0x57, 0x31, 0x70, 0x4b, 0x51, 0x4a, 0x41, 0x76,
+        0x6c, 0x54, 0x30, 0x46, 0x59, 0x48, 0x72, 0x77, 0x53, 0x55, 0x4a, 0x51,
+        0x35, 0x31, 0x4a, 0x72, 0x5a, 0x45, 0x55, 0x4a, 0x6a, 0x46, 0x78, 0x5a,
+        0x33, 0x38, 0x78, 0x78, 0x59, 0x48, 0x41, 0x30, 0x48, 0x4d, 0x66, 0x66,
+        0x55, 0x69, 0x44, 0x63, 0x7a, 0x71, 0x6b, 0x46, 0x6a, 0x30, 0x38, 0x77,
+        0x35, 0x39, 0x47, 0x2f, 0x36, 0x35, 0x32, 0x4a, 0x59, 0x2f, 0x68, 0x57,
+        0x70, 0x6f, 0x4d, 0x39, 0x75, 0x7a, 0x77, 0x5a, 0x50, 0x2b, 0x74, 0x56,
+        0x34, 0x73, 0x43, 0x57, 0x58, 0x46, 0x46, 0x35, 0x49, 0x75, 0x42, 0x42,
+        0x38, 0x50, 0x46, 0x77, 0x61, 0x65, 0x71, 0x67, 0x58, 0x44, 0x77, 0x72,
+        0x62, 0x78, 0x67, 0x59, 0x4d, 0x6a, 0x43, 0x67, 0x6b, 0x39, 0x6e, 0x4e,
+        0x5a, 0x75, 0x76, 0x64, 0x73, 0x64, 0x61, 0x56, 0x31, 0x62, 0x47, 0x52,
+        0x51, 0x3d, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x05, 0x6c,
+        0x69, 0x73, 0x74, 0x65, 0x6e, 0x2d, 0x70, 0x6f, 0x72, 0x74, 0x31, 0x33,
+        0x33, 0x30, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x46, 0x72,
+        0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x2e, 0x72,
+        0x65, 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f,
+        0x73, 0x74, 0x61, 0x74, 0x2e, 0x76, 0x6d, 0x2e, 0x62, 0x79, 0x74, 0x65,
+        0x6d, 0x61, 0x6e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x6e,
+        0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x6d,
+        0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x63,
+        0x65, 0x69, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+        0x24, 0x76, 0x6d, 0x2d, 0x69, 0x64, 0x66, 0x35, 0x62, 0x34, 0x63, 0x63,
+        0x34, 0x34, 0x2d, 0x30, 0x36, 0x66, 0x32, 0x2d, 0x34, 0x38, 0x34, 0x37,
+        0x2d, 0x39, 0x37, 0x64, 0x33, 0x2d, 0x62, 0x35, 0x62, 0x30, 0x62, 0x31,
+        0x39, 0x38, 0x66, 0x38, 0x34, 0x33 // slice C end
+    };
+    
+    private static final byte[] ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_A = new byte[] {
+        0x00, 0x00, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45,
+        0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44,
+        0x00, 0x00, 0x00, 0x08, // 8 parameters 
+    };
+    
+    private static final byte[] ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_B = new byte[] {
+        0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x15, 0x61, 0x63, 0x74, 0x69,
+        0x6f, 0x6e, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x76, 0x6d, 0x2d, 0x62, 0x79,
+        0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2d, 0x69, 0x6e, 0x73, 0x74, 0x72, 0x75,
+        0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x58,
+        0x61, 0x75, 0x74, 0x68, 0x2d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2f, 0x55,
+        0x46, 0x44, 0x76, 0x39, 0x50, 0x54, 0x33, 0x6e, 0x4c, 0x4d, 0x57, 0x31,
+        0x6c, 0x45, 0x4a, 0x55, 0x79, 0x54, 0x78, 0x66, 0x49, 0x48, 0x66, 0x55,
+        0x38, 0x62, 0x52, 0x78, 0x63, 0x41, 0x77, 0x34, 0x49, 0x64, 0x56, 0x59,
+        0x4c, 0x37, 0x4a, 0x7a, 0x48, 0x52, 0x4f, 0x72, 0x75, 0x7a, 0x4e, 0x76,
+        0x49, 0x70, 0x75, 0x76, 0x71, 0x72, 0x4c, 0x55, 0x4e, 0x30, 0x31, 0x66,
+        0x30, 0x68, 0x47, 0x49, 0x47, 0x4d, 0x6d, 0x7a, 0x63, 0x35, 0x38, 0x69,
+        0x79, 0x6c, 0x72, 0x62, 0x70, 0x67, 0x59, 0x31, 0x77, 0x6b, 0x55, 0x41,
+        0x30, 0x34, 0x59, 0x4c, 0x35, 0x57, 0x4f, 0x46, 0x36, 0x36, 0x79, 0x73,
+        0x66, 0x77, 0x4c, 0x57, 0x77, 0x44, 0x41, 0x38, 0x4d, 0x32, 0x52, 0x37,
+        0x6b, 0x68, 0x72, 0x4b, 0x30, 0x78, 0x59, 0x36, 0x2b, 0x44, 0x4c, 0x53,
+        0x41, 0x31, 0x6e, 0x4f, 0x55, 0x54, 0x2b, 0x69, 0x68, 0x6d, 0x76, 0x47,
+        0x73, 0x72, 0x6c, 0x6b, 0x35, 0x31, 0x78, 0x35, 0x61, 0x71, 0x48, 0x37,
+        0x56, 0x76, 0x71, 0x71, 0x6a, 0x2b, 0x54, 0x44, 0x79, 0x6a, 0x38, 0x5a,
+        0x33, 0x47, 0x6c, 0x33, 0x64, 0x4d, 0x70, 0x36, 0x4b, 0x45, 0x6e, 0x67,
+        0x74, 0x42, 0x78, 0x78, 0x68, 0x78, 0x4f, 0x2f, 0x70, 0x49, 0x39, 0x65,
+        0x75, 0x51, 0x47, 0x55, 0x69, 0x77, 0x57, 0x47, 0x63, 0x59, 0x37, 0x43,
+        0x64, 0x54, 0x41, 0x6f, 0x54, 0x53, 0x78, 0x32, 0x77, 0x68, 0x38, 0x62,
+        0x4f, 0x73, 0x6d, 0x44, 0x55, 0x6c, 0x6c, 0x77, 0x4f, 0x45, 0x37, 0x39,
+        0x37, 0x38, 0x5a, 0x68, 0x54, 0x52, 0x73, 0x53, 0x4e, 0x30, 0x62, 0x64,
+        0x35, 0x37, 0x65, 0x79, 0x6e, 0x44, 0x61, 0x61, 0x65, 0x32, 0x33, 0x54,
+        0x77, 0x49, 0x6e, 0x68, 0x65, 0x7a, 0x35, 0x69, 0x48, 0x4f, 0x78, 0x75,
+        0x57, 0x6c, 0x42, 0x79, 0x6a, 0x45, 0x76, 0x34, 0x52, 0x79, 0x44, 0x50,
+        0x53, 0x63, 0x30, 0x66, 0x41, 0x53, 0x6f, 0x4b, 0x77, 0x48, 0x37, 0x49,
+        0x41, 0x6a, 0x37, 0x56, 0x59, 0x4d, 0x7a, 0x75, 0x6a, 0x37, 0x32, 0x2f,
+        0x63, 0x39, 0x78, 0x4c, 0x4f, 0x41, 0x35, 0x34, 0x58, 0x75, 0x79, 0x72,
+        0x75, 0x61, 0x4d, 0x64, 0x71, 0x69, 0x30, 0x7a, 0x6c, 0x41, 0x34, 0x76,
+        0x2f, 0x61, 0x66, 0x37, 0x78, 0x4a, 0x39, 0x30, 0x58, 0x56, 0x4d, 0x57,
+        0x64, 0x57, 0x39, 0x36, 0x45, 0x47, 0x42, 0x47, 0x6b, 0x49, 0x6c, 0x6f,
+        0x33, 0x33, 0x66, 0x41, 0x3d, 0x3d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
+        0x00, 0x01, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2d, 0x61, 0x63,
+        0x74, 0x69, 0x6f, 0x6e, 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x02,
+        0x1a, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2d, 0x72, 0x75, 0x6c,
+        0x65, 0x52, 0x55, 0x4c, 0x45, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20,
+        0x73, 0x6c, 0x65, 0x65, 0x70, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,
+        0x20, 0x69, 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+        0x0a, 0x43, 0x4c, 0x41, 0x53, 0x53, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x72,
+        0x65, 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f,
+        0x73, 0x74, 0x61, 0x74, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e,
+        0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69,
+        0x74, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x0a, 0x4d, 0x45, 0x54, 0x48, 0x4f,
+        0x44, 0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x0a, 0x41, 0x54, 0x20, 0x45,
+        0x4e, 0x54, 0x52, 0x59, 0x0a, 0x49, 0x46, 0x20, 0x74, 0x72, 0x75, 0x65,
+        0x0a, 0x44, 0x4f, 0x0a, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e,
+        0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x28, 0x22, 0x73, 0x6c,
+        0x65, 0x65, 0x70, 0x2d, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22,
+        0x29, 0x0a, 0x45, 0x4e, 0x44, 0x52, 0x55, 0x4c, 0x45, 0x0a, 0x0a, 0x52,
+        0x55, 0x4c, 0x45, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x73, 0x6c, 0x65,
+        0x65, 0x70, 0x20, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x69, 0x6e,
+        0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f,
+        0x20, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x0a,
+        0x43, 0x4c, 0x41, 0x53, 0x53, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x72, 0x65,
+        0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f, 0x73,
+        0x74, 0x61, 0x74, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2e,
+        0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x74,
+        0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x0a, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44,
+    };
+    
+    private static final byte[] ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_C = new byte[] {
+        0x20, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x0a, 0x48, 0x45, 0x4c, 0x50, 0x45,
+        0x52, 0x20, 0x6f, 0x72, 0x67, 0x2e, 0x6a, 0x62, 0x6f, 0x73, 0x73, 0x2e,
+        0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x6e, 0x2e, 0x74, 0x68, 0x65, 0x72,
+        0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x2e, 0x68, 0x65, 0x6c, 0x70, 0x65,
+        0x72, 0x2e, 0x54, 0x68, 0x65, 0x72, 0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74,
+        0x48, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x0a, 0x41, 0x54, 0x20, 0x45, 0x4e,
+        0x54, 0x52, 0x59, 0x0a, 0x42, 0x49, 0x4e, 0x44, 0x20, 0x63, 0x6f, 0x75,
+        0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x20, 0x69,
+        0x6e, 0x74, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x61, 0x64, 0x43, 0x6f, 0x75,
+        0x6e, 0x74, 0x65, 0x72, 0x28, 0x22, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x2d,
+        0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x29, 0x0a, 0x49, 0x46,
+        0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75,
+        0x65, 0x20, 0x25, 0x20, 0x31, 0x30, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x0a,
+        0x44, 0x4f, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x28, 0x22, 0x63, 0x6f, 0x6d,
+        0x2e, 0x72, 0x65, 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72,
+        0x6d, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d,
+        0x61, 0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x49, 0x6e, 0x66, 0x69,
+        0x6e, 0x69, 0x74, 0x65, 0x4c, 0x6f, 0x6f, 0x70, 0x22, 0x2c, 0x20, 0x20,
+        0x22, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x20, 0x73, 0x6c, 0x65, 0x65,
+        0x70, 0x28, 0x29, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x2c, 0x20,
+        0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65,
+        0x29, 0x3b, 0x0a, 0x45, 0x4e, 0x44, 0x52, 0x55, 0x4c, 0x45, 0x0a, 0x00,
+        0x00, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x58, 0x63, 0x6c, 0x69, 0x65, 0x6e,
+        0x74, 0x2d, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x4d, 0x64, 0x4a, 0x30, 0x38,
+        0x6c, 0x51, 0x34, 0x2b, 0x34, 0x48, 0x39, 0x61, 0x73, 0x4f, 0x51, 0x61,
+        0x59, 0x78, 0x56, 0x36, 0x58, 0x44, 0x58, 0x62, 0x49, 0x43, 0x69, 0x33,
+        0x6e, 0x6a, 0x49, 0x37, 0x4a, 0x6d, 0x5a, 0x39, 0x57, 0x38, 0x57, 0x67,
+        0x4e, 0x37, 0x4c, 0x57, 0x38, 0x52, 0x49, 0x59, 0x5a, 0x30, 0x61, 0x43,
+        0x46, 0x70, 0x61, 0x48, 0x51, 0x49, 0x48, 0x73, 0x47, 0x33, 0x38, 0x6d,
+        0x4f, 0x4c, 0x76, 0x5a, 0x52, 0x7a, 0x4c, 0x4e, 0x77, 0x49, 0x34, 0x35,
+        0x4e, 0x47, 0x2f, 0x71, 0x6f, 0x78, 0x56, 0x75, 0x2b, 0x42, 0x41, 0x38,
+        0x65, 0x6b, 0x45, 0x42, 0x70, 0x4c, 0x6c, 0x48, 0x43, 0x6f, 0x74, 0x78,
+        0x4c, 0x6b, 0x2b, 0x31, 0x46, 0x37, 0x79, 0x5a, 0x6f, 0x6e, 0x6d, 0x6b,
+        0x45, 0x66, 0x58, 0x71, 0x36, 0x6f, 0x34, 0x69, 0x6d, 0x73, 0x56, 0x55,
+        0x2f, 0x38, 0x45, 0x55, 0x33, 0x36, 0x44, 0x68, 0x37, 0x59, 0x52, 0x64,
+        0x35, 0x71, 0x4f, 0x6e, 0x65, 0x72, 0x4a, 0x37, 0x4e, 0x49, 0x74, 0x72,
+        0x77, 0x2f, 0x6b, 0x42, 0x75, 0x56, 0x61, 0x41, 0x6c, 0x73, 0x56, 0x4c,
+        0x32, 0x42, 0x62, 0x6a, 0x37, 0x72, 0x79, 0x76, 0x56, 0x56, 0x45, 0x30,
+        0x31, 0x47, 0x67, 0x4d, 0x4a, 0x6c, 0x42, 0x4c, 0x51, 0x6a, 0x6e, 0x6a,
+        0x62, 0x32, 0x31, 0x65, 0x4f, 0x32, 0x79, 0x67, 0x32, 0x77, 0x34, 0x41,
+        0x4b, 0x44, 0x4f, 0x67, 0x67, 0x48, 0x4d, 0x77, 0x63, 0x43, 0x41, 0x61,
+        0x5a, 0x6c, 0x31, 0x77, 0x57, 0x31, 0x70, 0x4b, 0x51, 0x4a, 0x41, 0x76,
+        0x6c, 0x54, 0x30, 0x46, 0x59, 0x48, 0x72, 0x77, 0x53, 0x55, 0x4a, 0x51,
+        0x35, 0x31, 0x4a, 0x72, 0x5a, 0x45, 0x55, 0x4a, 0x6a, 0x46, 0x78, 0x5a,
+        0x33, 0x38, 0x78, 0x78, 0x59, 0x48, 0x41, 0x30, 0x48, 0x4d, 0x66, 0x66,
+        0x55, 0x69, 0x44, 0x63, 0x7a, 0x71, 0x6b, 0x46, 0x6a, 0x30, 0x38, 0x77,
+        0x35, 0x39, 0x47, 0x2f, 0x36, 0x35, 0x32, 0x4a, 0x59, 0x2f, 0x68, 0x57,
+        0x70, 0x6f, 0x4d, 0x39, 0x75, 0x7a, 0x77, 0x5a, 0x50, 0x2b, 0x74, 0x56,
+        0x34, 0x73, 0x43, 0x57, 0x58, 0x46, 0x46, 0x35, 0x49, 0x75, 0x42, 0x42,
+        0x38, 0x50, 0x46, 0x77, 0x61, 0x65, 0x71, 0x67, 0x58, 0x44, 0x77, 0x72,
+        0x62, 0x78, 0x67, 0x59, 0x4d, 0x6a, 0x43, 0x67, 0x6b, 0x39, 0x6e, 0x4e,
+        0x5a, 0x75, 0x76, 0x64, 0x73, 0x64, 0x61, 0x56, 0x31, 0x62, 0x47, 0x52,
+        0x51, 0x3d, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x05, 0x6c,
+        0x69, 0x73, 0x74, 0x65, 0x6e, 0x2d, 0x70, 0x6f, 0x72, 0x74, 0x31, 0x33,
+        0x33, 0x30, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x46, 0x72,
+        0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x2e, 0x72,
+        0x65, 0x64, 0x68, 0x61, 0x74, 0x2e, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x6f,
+        0x73, 0x74, 0x61, 0x74, 0x2e, 0x76, 0x6d, 0x2e, 0x62, 0x79, 0x74, 0x65,
+        0x6d, 0x61, 0x6e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x69, 0x6e,
+        0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x6d,
+        0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x65, 0x63,
+        0x65, 0x69, 0x76, 0x65, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+        0x24, 0x76, 0x6d, 0x2d, 0x69, 0x64, 0x66, 0x35, 0x62, 0x34, 0x63, 0x63,
+        0x34, 0x34, 0x2d, 0x30, 0x36, 0x66, 0x32, 0x2d, 0x34, 0x38, 0x34, 0x37,
+        0x2d, 0x39, 0x37, 0x64, 0x33, 0x2d, 0x62, 0x35, 0x62, 0x30, 0x62, 0x31,
+        0x39, 0x38, 0x66, 0x38, 0x34, 0x33
+    };
+    
+    /*
+     * This is serialized format for
+     * req = new Request(RequestType.RESPONSE_EXPECTED, blah)
+     */
+    private static final byte[] ENCODED_REQUEST_WITH_NO_PARAMS = new byte[] {
+        0x00, 0x00, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45,
+        0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, 0x00, 0x00, 0x00,
+        0x00
+    };
+    
+    private static final byte[][] GARBAGE_AS_REQUEST = new byte[][] {
+            // general garbage
+            { 0x0d, 0x0b, 0x0e, 0x0e, 0x0f },
+            // first two bytes are broken
+            { 0x0f, 0x0d, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53,
+                    0x45, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44,
+                    0x00, 0x00, 0x00, 0x00 },
+            // last byte indicates params, which are missing
+            { 0x00, 0x00, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53,
+                    0x45, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44,
+                    0x00, 0x00, 0x00, 0x0f } };
+    
+    
+    private static final byte[] TYPE = RequestType.RESPONSE_EXPECTED.toString().getBytes();
+
+    private ChannelHandlerContext ctx;
+    private CommandChannelRequestDecoder decoder;
+
+    @Before
+    public void setUp() {
+        ctx = mock(ChannelHandlerContext.class);
+        when(ctx.channel()).thenReturn(mock(Channel.class));
+        decoder = new CommandChannelRequestDecoder();
+    }
+
+    @Test
+    public void testDecode() throws Exception {
+        ByteBuf buffer = Unpooled.buffer();
+        buffer.writeInt(TYPE.length);
+        buffer.writeBytes(TYPE);
+        buffer.writeInt(0);
+
+        List<Object> resultList = new ArrayList<>();
+        decoder.decode(ctx, buffer, resultList);
+        assertEquals(1, resultList.size());
+        Request request = (Request)resultList.get(0);
+        assertTrue(RequestType.RESPONSE_EXPECTED == (RequestType) request.getType());
+    }
+
+    @Test
+    public void testDecodeWithParameters() throws Exception {
+        String parmName = "parameter";
+        String parmValue = "hello";
+        ByteBuf buffer = Unpooled.buffer();
+        buffer.writeInt(TYPE.length);
+        buffer.writeBytes(TYPE);
+        buffer.writeInt(1);
+        buffer.writeInt(parmName.getBytes().length);
+        buffer.writeInt(parmValue.getBytes().length);
+        buffer.writeBytes(parmName.getBytes());
+        buffer.writeBytes(parmValue.getBytes());
+        
+        List<Object> resultList = new ArrayList<>();
+        decoder.decode(ctx, buffer, resultList);
+        assertEquals(1, resultList.size());
+        Request request = (Request) resultList.get(0);
+        Collection<String> parmNames = request.getParameterNames();
+
+        assertEquals(1, parmNames.size());
+        assertTrue(parmNames.contains(parmName));
+        String decodedValue = request.getParameter(parmName);
+        assertEquals(parmValue, decodedValue);
+    }
+    
+    @Test
+    public void testDecodeWithLongParams() throws Exception {
+        String parmName = "parameter";
+        String param2Name = "foo-bar";
+        String param2Value = "RESPONSE_EXPECTED";
+        ByteBuf buffer = Unpooled.buffer();
+        buffer.writeInt(TYPE.length);
+        buffer.writeBytes(TYPE);
+        buffer.writeInt(2);
+        buffer.writeInt(parmName.getBytes().length);
+        buffer.writeInt(LONG_PARAM_VALUE.getBytes().length);
+        buffer.writeBytes(parmName.getBytes());
+        buffer.writeBytes(LONG_PARAM_VALUE.getBytes());
+        buffer.writeInt(param2Name.getBytes().length);
+        buffer.writeInt(param2Value.getBytes().length);
+        buffer.writeBytes(param2Name.getBytes());
+        buffer.writeBytes(param2Value.getBytes());
+        
+        List<Object> resultList = new ArrayList<>();
+        decoder.decode(ctx, buffer, resultList);
+        assertEquals(1, resultList.size());
+        Request request = (Request) resultList.get(0);
+        Collection<String> parmNames = request.getParameterNames();
+
+        assertEquals(2, parmNames.size());
+        assertTrue(parmNames.contains(parmName));
+        String decodedValue = request.getParameter(parmName);
+        assertEquals(LONG_PARAM_VALUE, decodedValue);
+    }
+    
+    @Test
+    public void testDecodeWithParametersFromBytesArray() throws Exception {
+        ByteBuf buffer = Unpooled.copiedBuffer(ENCODED_REQUEST_WITH_PARAMS);
+        Request expected = new Request(RequestType.RESPONSE_EXPECTED, null);
+        expected.setParameter("param1", "value1");
+        expected.setParameter("param2", "value2");
+        List<Object> resultList = new ArrayList<>();
+        new CommandChannelRequestDecoder().decode(ctx, buffer, resultList);
+        assertEquals(1, resultList.size());
+        Message actual = (Message)resultList.get(0);
+        assertTrue(actual instanceof Request);
+        assertTrue(Messages.equal(expected, (Request)actual));
+        InetSocketAddress addr = new InetSocketAddress(1234);
+        buffer = Unpooled.copiedBuffer(ENCODED_REQUEST_WITH_NO_PARAMS);
+        expected = new Request(RequestType.RESPONSE_EXPECTED, addr);
+        resultList = new ArrayList<>();
+        new CommandChannelRequestDecoder().decode(ctx, buffer, resultList);
+        assertEquals(1, resultList.size());
+        actual = (Message)resultList.get(0);
+        assertTrue(actual instanceof Request);
+        assertTrue(Messages.equal(expected, (Request)actual));
+    }
+    
+    /**
+     * Tests the case where the decode() method is called multiple times due
+     * to some data not yet available so as to be able to decode the request in
+     * it's entirety.
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void testDecodeWithParamsFromBytes() throws Exception {
+        CommandChannelRequestDecoder decoder = new CommandChannelRequestDecoder();
+
+        // First decode all-at-once
+        List<Object> allAtOnceResultList = new ArrayList<>();
+        ByteBuf firstBuffer = Unpooled.copiedBuffer(ENCODED_REQUEST_WITH_MANY_PARAMS);
+        decoder.decode(ctx, firstBuffer, allAtOnceResultList);
+        assertEquals(1, allAtOnceResultList.size());
+        Message firstActual = (Message)allAtOnceResultList.get(0);
+        assertTrue(firstActual instanceof Request);
+        Request firstRequest = (Request)firstActual;
+        
+        List<Object> resultList = new ArrayList<>();
+        ByteBuf buffer = Unpooled.copiedBuffer(ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_A);
+        int bytesAvailable = ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_A.length;
+        assertEquals(bytesAvailable, buffer.readableBytes());
+        decoder.decode(ctx, buffer, resultList); // request type got decoded
+        assertEquals(bytesAvailable, buffer.readableBytes());
+        assertEquals(0, resultList.size());
+        ByteBuf remaining = Unpooled.copiedBuffer(buffer);
+        assertEquals(bytesAvailable, remaining.array().length);
+        buffer = Unpooled.copiedBuffer(remaining.array(), ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_B);
+        bytesAvailable = remaining.array().length + ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_B.length;
+        assertEquals(bytesAvailable, buffer.readableBytes());
+        decoder.decode(ctx, buffer, resultList); // nothing additional should get decoded
+        assertEquals(bytesAvailable, buffer.readableBytes());
+        assertEquals(0, resultList.size());
+        buffer = Unpooled.copiedBuffer(remaining.array(),
+                             ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_B,
+                             ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_C);
+        bytesAvailable = remaining.array().length +
+                           ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_B.length +
+                           ENCODED_INCOMPLETE_REQUEST_WITH_MANY_PARAMS_C.length;
+        assertEquals(bytesAvailable, buffer.readableBytes());
+        decoder.decode(ctx, buffer, resultList); // this time decoding should complete
+        assertEquals(0, buffer.readableBytes());
+        assertEquals(1, resultList.size());
+        Message actual = (Message)resultList.get(0);
+        assertTrue(actual instanceof Request);
+        Request actualReq = (Request) actual;
+        assertEquals(RequestType.RESPONSE_EXPECTED, actualReq.getType());
+        assertEquals("Expected 8 parameters", 8, actualReq.getParameterNames().size());
+        assertEquals(Integer.toString(0), actualReq.getParameter("byteman-action"));
+        String rule = actualReq.getParameter("byteman-rule");
+        assertNotNull(rule);
+        assertEquals(538, rule.length());
+        assertTrue(Messages.equal(firstRequest, actualReq));
+    }
+    
+    @Test
+    public void decodingOfGarbageDoesNotAddToResultList()
+            throws Exception {
+        for (int i = 0; i < GARBAGE_AS_REQUEST.length; i++) {
+            ByteBuf buffer = Unpooled
+                    .copiedBuffer(GARBAGE_AS_REQUEST[0]);
+            CommandChannelRequestDecoder decoder = new CommandChannelRequestDecoder();
+            List<Object> outList = new ArrayList<>();
+            decoder.decode(ctx, buffer, outList);
+            assertEquals(0, outList.size());
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/JsonResponseParserTest.java	Thu May 12 15:46:30 2016 +0200
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012-2016 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * Thermostat is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.agent.command.server.internal;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ByteChannel;
+import java.nio.charset.Charset;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.redhat.thermostat.common.command.Response;
+import com.redhat.thermostat.common.command.Response.ResponseType;
+
+public class JsonResponseParserTest {
+    
+    private ByteChannel agentChannel;
+    private JsonResponseParser parser;
+
+    @Before
+    public void setUp() {
+        agentChannel = mock(ByteChannel.class);
+        parser = new JsonResponseParser();
+    }
+
+    @Test
+    public void testSuccess() throws IOException {
+        JsonObject jsonResponse = createResponse();
+        byte[] encoded = toJson(jsonResponse);
+        mockByteChannel(encoded);
+        
+        Response response = parser.parseResponse(agentChannel);
+        assertEquals(ResponseType.OK, response.getType());
+    }
+    
+    @Test(expected=IOException.class)
+    public void testEmpty() throws IOException {
+        mockByteChannel(new byte[0]);
+        parser.parseResponse(agentChannel);
+    }
+    
+    @Test(expected=IOException.class)
+    public void testNotJson() throws IOException {
+        mockByteChannel("Not JSON".getBytes(Charset.forName("UTF-8")));
+        parser.parseResponse(agentChannel);
+    }
+    
+    @Test(expected=IOException.class)
+    public void testBadResponseRoot() throws IOException {
+        byte[] encoded = toJson(new JsonArray());
+        mockByteChannel(encoded);
+        parser.parseResponse(agentChannel);
+    }
+    
+    @Test(expected=IOException.class)
+    public void testParamsMissing() throws IOException {
+        byte[] encoded = toJson(new JsonObject());
+        mockByteChannel(encoded);
+        parser.parseResponse(agentChannel);
+    }
+    
+    @Test(expected=IOException.class)
+    public void testBadParams() throws IOException {
+        JsonObject jsonResponse = createResponse();
+        jsonResponse.add(CommandChannelConstants.RESPONSE_JSON_TOP, new JsonArray());
+        
+        byte[] encoded = toJson(new JsonObject());
+        mockByteChannel(encoded);
+        parser.parseResponse(agentChannel);
+    }
+    
+    @Test(expected=IOException.class)
+    public void testNullParams() throws IOException {
+        JsonObject jsonResponse = createResponse();
+        jsonResponse.add(CommandChannelConstants.RESPONSE_JSON_TOP, null);
+        
+        byte[] encoded = toJson(new JsonObject());
+        mockByteChannel(encoded);
+        parser.parseResponse(agentChannel);
+    }
+    
+    @Test(expected=IOException.class)
+    public void testResponseTypeMissing() throws IOException {
+        JsonObject root = createResponse();
+        JsonObject jsonResponse = root.get(CommandChannelConstants.RESPONSE_JSON_TOP).getAsJsonObject();
+        jsonResponse.remove(CommandChannelConstants.RESPONSE_JSON_TYPE);
+        
+        byte[] encoded = toJson(root);
+        mockByteChannel(encoded);
+        parser.parseResponse(agentChannel);
+    }
+    
+    @Test(expected=IOException.class)
+    public void testResponseTypeNotString() throws IOException {
+        JsonObject root = createResponse();
+        JsonObject jsonResponse = root.get(CommandChannelConstants.RESPONSE_JSON_TOP).getAsJsonObject();
+        jsonResponse.add(CommandChannelConstants.RESPONSE_JSON_TYPE, new JsonArray());
+        
+        byte[] encoded = toJson(root);
+        mockByteChannel(encoded);
+        parser.parseResponse(agentChannel);
+    }
+    
+    @Test(expected=IOException.class)
+    public void testResponseTypeNull() throws IOException {
+        JsonObject root = createResponse();
+        JsonObject jsonResponse = root.get(CommandChannelConstants.RESPONSE_JSON_TOP).getAsJsonObject();
+        jsonResponse.addProperty(CommandChannelConstants.RESPONSE_JSON_TYPE, (String) null);
+        
+        byte[] encoded = toJson(root);
+        mockByteChannel(encoded);
+        parser.parseResponse(agentChannel);
+    }
+    
+    @Test(expected=IOException.class)
+    public void testResponseTypeNotEnum() throws IOException {
+        JsonObject root = createResponse();
+        JsonObject jsonResponse = root.get(CommandChannelConstants.RESPONSE_JSON_TOP).getAsJsonObject();
+        jsonResponse.addProperty(CommandChannelConstants.RESPONSE_JSON_TYPE, "Not a ResponseType");
+        
+        byte[] encoded = toJson(root);
+        mockByteChannel(encoded);
+        parser.parseResponse(agentChannel);
+    }
+
+    private JsonObject createResponse() {
+        JsonObject params = new JsonObject();
+        params.addProperty(CommandChannelConstants.RESPONSE_JSON_TYPE, ResponseType.OK.name());
+        JsonObject root = new JsonObject();
+        root.add(CommandChannelConstants.RESPONSE_JSON_TOP, params);
+        return root;
+    }
+    
+    private byte[] toJson(JsonElement element) {
+        Gson gson = new GsonBuilder().serializeNulls().create();
+        String jsonString = gson.toJson(element);
+        return jsonString.getBytes(Charset.forName("UTF-8"));
+    }
+
+    private void mockByteChannel(final byte[] encoded) throws IOException {
+        when(agentChannel.read(any(ByteBuffer.class))).thenAnswer(new Answer<Integer>() {
+            @Override
+            public Integer answer(InvocationOnMock invocation) throws Throwable {
+                ByteBuffer buf = (ByteBuffer) invocation.getArguments()[0];
+                buf.put(encoded);
+                buf.flip();
+                return encoded.length;
+            }
+        });
+    }
+
+}
--- a/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/RequestDecoderTest.java	Thu May 12 11:17:00 2016 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.agent.command.server.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.redhat.thermostat.common.command.Message;
-import com.redhat.thermostat.common.command.Messages;
-import com.redhat.thermostat.common.command.Request;
-import com.redhat.thermostat.common.command.Request.RequestType;
-
-import io.netty.buffer.ByteBuf;
-import io.netty.buffer.Unpooled;
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelHandlerContext;
-
-public class RequestDecoderTest {
-    
-    /*
-     * This is serialized format for
-     * req = new Request(RequestType.RESPONSE_EXPECTED, blah)
-     * req.setParameter("param1", "value1");
-     * req.setParameter("param2", "value2");
-     */
-    private static final byte[] ENCODED_REQEUEST_WITH_PARAMS = new byte[] {
-        0x00, 0x00, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45,
-        0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, 0x00, 0x00, 0x00,
-        0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x70, 0x61, 0x72,
-        0x61, 0x6d, 0x31, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x31, 0x00, 0x00, 0x00,
-        0x06, 0x00, 0x00, 0x00, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x32, 0x76,
-        0x61, 0x6c, 0x75, 0x65, 0x32
-    };
-    
-    /*
-     * This is serialized format for
-     * req = new Request(RequestType.RESPONSE_EXPECTED, blah)
-     */
-    private static final byte[] ENCODED_REQUEST_WITH_NO_PARAMS = new byte[] {
-        0x00, 0x00, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45,
-        0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44, 0x00, 0x00, 0x00,
-        0x00
-    };
-    
-    private static final byte[][] GARBAGE_AS_REQUEST = new byte[][] {
-            // general garbage
-            { 0x0d, 0x0b, 0x0e, 0x0e, 0x0f },
-            // first two bytes are broken
-            { 0x0f, 0x0d, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53,
-                    0x45, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44,
-                    0x00, 0x00, 0x00, 0x00 },
-            // last byte indicates params, which are missing
-            { 0x00, 0x00, 0x00, 0x11, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53,
-                    0x45, 0x5f, 0x45, 0x58, 0x50, 0x45, 0x43, 0x54, 0x45, 0x44,
-                    0x00, 0x00, 0x00, 0x0f } };
-    
-    
-    private static final byte[] TYPE = RequestType.RESPONSE_EXPECTED.toString().getBytes();
-
-    private ChannelHandlerContext ctx;
-    private CommandChannelRequestDecoder decoder;
-
-    @Before
-    public void setUp() {
-        ctx = mock(ChannelHandlerContext.class);
-        when(ctx.channel()).thenReturn(mock(Channel.class));
-        decoder = new CommandChannelRequestDecoder();
-    }
-
-    @Test
-    public void testDecode() throws Exception {
-        ByteBuf buffer = Unpooled.buffer();
-        buffer.writeInt(TYPE.length);
-        buffer.writeBytes(TYPE);
-        buffer.writeInt(0);
-
-        List<Object> resultList = new ArrayList<>();
-        decoder.decode(ctx, buffer, resultList);
-        assertEquals(1, resultList.size());
-        Request request = (Request)resultList.get(0);
-        assertTrue(RequestType.RESPONSE_EXPECTED == (RequestType) request.getType());
-    }
-
-    @Test
-    public void testDecodeWithParameters() throws Exception {
-        String parmName = "parameter";
-        String parmValue = "hello";
-        ByteBuf buffer = Unpooled.buffer();
-        buffer.writeInt(TYPE.length);
-        buffer.writeBytes(TYPE);
-        buffer.writeInt(1);
-        buffer.writeInt(parmName.getBytes().length);
-        buffer.writeInt(parmValue.getBytes().length);
-        buffer.writeBytes(parmName.getBytes());
-        buffer.writeBytes(parmValue.getBytes());
-        
-        List<Object> resultList = new ArrayList<>();
-        decoder.decode(ctx, buffer, resultList);
-        assertEquals(1, resultList.size());
-        Request request = (Request) resultList.get(0);
-        Collection<String> parmNames = request.getParameterNames();
-
-        assertEquals(1, parmNames.size());
-        assertTrue(parmNames.contains(parmName));
-        String decodedValue = request.getParameter(parmName);
-        assertEquals(parmValue, decodedValue);
-    }
-    
-    @Test
-    public void testDecodeWithParametersFromBytesArray() throws Exception {
-        ByteBuf buffer = Unpooled.copiedBuffer(ENCODED_REQEUEST_WITH_PARAMS);
-        Request expected = new Request(RequestType.RESPONSE_EXPECTED, null);
-        expected.setParameter("param1", "value1");
-        expected.setParameter("param2", "value2");
-        List<Object> resultList = new ArrayList<>();
-        new CommandChannelRequestDecoder().decode(ctx, buffer, resultList);
-        assertEquals(1, resultList.size());
-        Message actual = (Message)resultList.get(0);
-        assertTrue(actual instanceof Request);
-        assertTrue(Messages.equal(expected, (Request)actual));
-        InetSocketAddress addr = new InetSocketAddress(1234);
-        buffer = Unpooled.copiedBuffer(ENCODED_REQUEST_WITH_NO_PARAMS);
-        expected = new Request(RequestType.RESPONSE_EXPECTED, addr);
-        resultList = new ArrayList<>();
-        new CommandChannelRequestDecoder().decode(ctx, buffer, resultList);
-        assertEquals(1, resultList.size());
-        actual = (Message)resultList.get(0);
-        assertTrue(actual instanceof Request);
-        assertTrue(Messages.equal(expected, (Request)actual));
-    }
-    
-    @Test
-    public void decodingOfGarbageDoesNotAddToResultList()
-            throws Exception {
-        for (int i = 0; i < GARBAGE_AS_REQUEST.length; i++) {
-            ByteBuf buffer = Unpooled
-                    .copiedBuffer(GARBAGE_AS_REQUEST[0]);
-            CommandChannelRequestDecoder decoder = new CommandChannelRequestDecoder();
-            List<Object> outList = new ArrayList<>();
-            decoder.decode(ctx, buffer, outList);
-            assertEquals(0, outList.size());
-        }
-    }
-}
-
--- a/agent/command-server/src/test/java/com/redhat/thermostat/agent/command/server/internal/ResponseParserTest.java	Thu May 12 11:17:00 2016 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,199 +0,0 @@
-/*
- * Copyright 2012-2016 Red Hat, Inc.
- *
- * This file is part of Thermostat.
- *
- * Thermostat is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 2, or (at your
- * option) any later version.
- *
- * Thermostat is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Thermostat; see the file COPYING.  If not see
- * <http://www.gnu.org/licenses/>.
- *
- * Linking this code with other modules is making a combined work
- * based on this code.  Thus, the terms and conditions of the GNU
- * General Public License cover the whole combination.
- *
- * As a special exception, the copyright holders of this code give
- * you permission to link this code with independent modules to
- * produce an executable, regardless of the license terms of these
- * independent modules, and to copy and distribute the resulting
- * executable under terms of your choice, provided that you also
- * meet, for each linked independent module, the terms and conditions
- * of the license of that module.  An independent module is a module
- * which is not derived from or based on this code.  If you modify
- * this code, you may extend this exception to your version of the
- * library, but you are not obligated to do so.  If you do not wish
- * to do so, delete this exception statement from your version.
- */
-
-package com.redhat.thermostat.agent.command.server.internal;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.ByteChannel;
-import java.nio.charset.Charset;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.redhat.thermostat.common.command.Response;
-import com.redhat.thermostat.common.command.Response.ResponseType;
-
-public class ResponseParserTest {
-    
-    private ByteChannel agentChannel;
-    private JsonResponseParser parser;
-
-    @Before
-    public void setUp() {
-        agentChannel = mock(ByteChannel.class);
-        parser = new JsonResponseParser();
-    }
-
-    @Test
-    public void testSuccess() throws IOException {
-        JsonObject jsonResponse = createResponse();
-        byte[] encoded = toJson(jsonResponse);
-        mockByteChannel(encoded);
-        
-        Response response = parser.parseResponse(agentChannel);
-        assertEquals(ResponseType.OK, response.getType());
-    }
-    
-    @Test(expected=IOException.class)
-    public void testEmpty() throws IOException {
-        mockByteChannel(new byte[0]);
-        parser.parseResponse(agentChannel);
-    }
-    
-    @Test(expected=IOException.class)
-    public void testNotJson() throws IOException {
-        mockByteChannel("Not JSON".getBytes(Charset.forName("UTF-8")));
-        parser.parseResponse(agentChannel);
-    }
-    
-    @Test(expected=IOException.class)
-    public void testBadResponseRoot() throws IOException {
-        byte[] encoded = toJson(new JsonArray());
-        mockByteChannel(encoded);
-        parser.parseResponse(agentChannel);
-    }
-    
-    @Test(expected=IOException.class)
-    public void testParamsMissing() throws IOException {
-        byte[] encoded = toJson(new JsonObject());
-        mockByteChannel(encoded);
-        parser.parseResponse(agentChannel);
-    }
-    
-    @Test(expected=IOException.class)
-    public void testBadParams() throws IOException {
-        JsonObject jsonResponse = createResponse();
-        jsonResponse.add(CommandChannelConstants.RESPONSE_JSON_TOP, new JsonArray());
-        
-        byte[] encoded = toJson(new JsonObject());
-        mockByteChannel(encoded);
-        parser.parseResponse(agentChannel);
-    }
-    
-    @Test(expected=IOException.class)
-    public void testNullParams() throws IOException {
-        JsonObject jsonResponse = createResponse();
-        jsonResponse.add(CommandChannelConstants.RESPONSE_JSON_TOP, null);
-        
-        byte[] encoded = toJson(new JsonObject());
-        mockByteChannel(encoded);
-        parser.parseResponse(agentChannel);
-    }
-    
-    @Test(expected=IOException.class)
-    public void testResponseTypeMissing() throws IOException {
-        JsonObject root = createResponse();
-        JsonObject jsonResponse = root.get(CommandChannelConstants.RESPONSE_JSON_TOP).getAsJsonObject();
-        jsonResponse.remove(CommandChannelConstants.RESPONSE_JSON_TYPE);
-        
-        byte[] encoded = toJson(root);
-        mockByteChannel(encoded);
-        parser.parseResponse(agentChannel);
-    }
-    
-    @Test(expected=IOException.class)
-    public void testResponseTypeNotString() throws IOException {
-        JsonObject root = createResponse();
-        JsonObject jsonResponse = root.get(CommandChannelConstants.RESPONSE_JSON_TOP).getAsJsonObject();
-        jsonResponse.add(CommandChannelConstants.RESPONSE_JSON_TYPE, new JsonArray());
-        
-        byte[] encoded = toJson(root);
-        mockByteChannel(encoded);
-        parser.parseResponse(agentChannel);
-    }
-    
-    @Test(expected=IOException.class)
-    public void testResponseTypeNull() throws IOException {
-        JsonObject root = createResponse();
-        JsonObject jsonResponse = root.get(CommandChannelConstants.RESPONSE_JSON_TOP).getAsJsonObject();
-        jsonResponse.addProperty(CommandChannelConstants.RESPONSE_JSON_TYPE, (String) null);
-        
-        byte[] encoded = toJson(root);
-        mockByteChannel(encoded);
-        parser.parseResponse(agentChannel);
-    }
-    
-    @Test(expected=IOException.class)
-    public void testResponseTypeNotEnum() throws IOException {
-        JsonObject root = createResponse();
-        JsonObject jsonResponse = root.get(CommandChannelConstants.RESPONSE_JSON_TOP).getAsJsonObject();
-        jsonResponse.addProperty(CommandChannelConstants.RESPONSE_JSON_TYPE, "Not a ResponseType");
-        
-        byte[] encoded = toJson(root);
-        mockByteChannel(encoded);
-        parser.parseResponse(agentChannel);
-    }
-
-    private JsonObject createResponse() {
-        JsonObject params = new JsonObject();
-        params.addProperty(CommandChannelConstants.RESPONSE_JSON_TYPE, ResponseType.OK.name());
-        JsonObject root = new JsonObject();
-        root.add(CommandChannelConstants.RESPONSE_JSON_TOP, params);
-        return root;
-    }
-    
-    private byte[] toJson(JsonElement element) {
-        Gson gson = new GsonBuilder().serializeNulls().create();
-        String jsonString = gson.toJson(element);
-        return jsonString.getBytes(Charset.forName("UTF-8"));
-    }
-
-    private void mockByteChannel(final byte[] encoded) throws IOException {
-        when(agentChannel.read(any(ByteBuffer.class))).thenAnswer(new Answer<Integer>() {
-            @Override
-            public Integer answer(InvocationOnMock invocation) throws Throwable {
-                ByteBuffer buf = (ByteBuffer) invocation.getArguments()[0];
-                buf.put(encoded);
-                buf.flip();
-                return encoded.length;
-            }
-        });
-    }
-
-}