You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cl...@apache.org on 2017/09/05 18:42:18 UTC

[2/2] activemq-artemis git commit: ARTEMIS-1384 adding CLI command (stat) to display basic queue stats

ARTEMIS-1384 adding CLI command (stat) to display basic queue stats


Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/87b570f7
Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/87b570f7
Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/87b570f7

Branch: refs/heads/master
Commit: 87b570f7ce6269f415635944435db0decb789f2d
Parents: dd6a5ab
Author: Pat Fox <pa...@gmail.com>
Authored: Sat Sep 2 01:29:04 2017 +0200
Committer: Clebert Suconic <cl...@apache.org>
Committed: Tue Sep 5 14:22:36 2017 -0400

----------------------------------------------------------------------
 .../apache/activemq/artemis/cli/Artemis.java    |   5 +-
 .../artemis/cli/commands/queue/StatQueue.java   | 262 ++++++++++++++
 .../apache/activemq/cli/test/ArtemisTest.java   | 343 +++++++++++++++++++
 .../activemq/cli/test/TestActionContext.java    |   8 +
 4 files changed, 616 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/87b570f7/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java
----------------------------------------------------------------------
diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java
index d52507d..6abf1b6 100644
--- a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java
+++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/Artemis.java
@@ -30,6 +30,7 @@ import org.apache.activemq.artemis.cli.commands.InputAbstract;
 import org.apache.activemq.artemis.cli.commands.InvalidOptionsError;
 import org.apache.activemq.artemis.cli.commands.Kill;
 import org.apache.activemq.artemis.cli.commands.Mask;
+import org.apache.activemq.artemis.cli.commands.queue.StatQueue;
 import org.apache.activemq.artemis.cli.commands.Run;
 import org.apache.activemq.artemis.cli.commands.Stop;
 import org.apache.activemq.artemis.cli.commands.address.CreateAddress;
@@ -152,8 +153,8 @@ public class Artemis {
       String instance = artemisInstance != null ? artemisInstance.getAbsolutePath() : System.getProperty("artemis.instance");
       Cli.CliBuilder<Action> builder = Cli.<Action>builder("artemis").withDescription("ActiveMQ Artemis Command Line").withCommand(HelpAction.class).withCommand(Producer.class).withCommand(Consumer.class).withCommand(Browse.class).withCommand(Mask.class).withDefaultCommand(HelpAction.class);
 
-      builder.withGroup("queue").withDescription("Queue tools group (create|delete|update) (example ./artemis queue create)").
-         withDefaultCommand(HelpQueue.class).withCommands(CreateQueue.class, DeleteQueue.class, UpdateQueue.class);
+      builder.withGroup("queue").withDescription("Queue tools group (create|delete|update|stat) (example ./artemis queue create)").
+         withDefaultCommand(HelpQueue.class).withCommands(CreateQueue.class, DeleteQueue.class, UpdateQueue.class, StatQueue.class);
 
       builder.withGroup("address").withDescription("Address tools group (create|delete|update|show) (example ./artemis address create)").
          withDefaultCommand(HelpAddress.class).withCommands(CreateAddress.class, DeleteAddress.class, UpdateAddress.class, ShowAddress.class);

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/87b570f7/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/queue/StatQueue.java
----------------------------------------------------------------------
diff --git a/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/queue/StatQueue.java b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/queue/StatQueue.java
new file mode 100644
index 0000000..1813033
--- /dev/null
+++ b/artemis-cli/src/main/java/org/apache/activemq/artemis/cli/commands/queue/StatQueue.java
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     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 org.apache.activemq.artemis.cli.commands.queue;
+
+import io.airlift.airline.Command;
+import io.airlift.airline.Option;
+import org.apache.activemq.artemis.api.core.JsonUtil;
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+import org.apache.activemq.artemis.api.core.management.ManagementHelper;
+import org.apache.activemq.artemis.cli.commands.AbstractAction;
+import org.apache.activemq.artemis.cli.commands.ActionContext;
+
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import java.util.Arrays;
+import java.util.HashMap;
+
+@Command(name = "stat", description = "prints out basic stats associated with queues. Output includes CONSUMER_COUNT (number of consumers), MESSAGE_COUNT (current message count on the queue, including scheduled, paged and in-delivery messages), MESSAGES_ADDED (messages added to the queue), DELIVERING_COUNT (messages broker is currently delivering to consumer(s)), MESSAGES_ACKED (messages acknowledged from the consumer(s))." + " Queues can be filtered using EITHER '--queueName X' where X is contained in the queue name OR using a full filter '--field NAME --operation EQUALS --value X'."
+
+)
+public class StatQueue extends AbstractAction {
+
+   public enum FIELD {
+
+      NAME("name"), ADDRESS("address"), CONSUMER_COUNT("consumerCount"), MESSAGE_COUNT("messageCount"), MESSAGES_ADDED("messagesAdded"), DELIVERING_COUNT("deliveringCount"), MESSAGES_ACKED("messagesAcked");
+
+      private String jsonId;
+
+      FIELD(String jsonId) {
+         this.jsonId = jsonId;
+      }
+
+      String getJsonId() {
+         return this.jsonId;
+      }
+
+   }
+
+   public enum OPERATION {
+      CONTAINS, EQUALS
+   }
+
+   @Option(name = "--queueName", description = "display queue stats for queue(s) with names containing this string.")
+   private String queueName;
+
+   @Option(name = "--field", description = "field to use in filter. Possible values NAME, ADDRESS, MESSAGE_COUNT, MESSAGES_ADDED, DELIVERING_COUNT, MESSAGES_ACKED.")
+   private String fieldName;
+
+   @Option(name = "--operation", description = "operation to use in filter. Possible values CONTAINS, EQUALS.")
+   private String operationName;
+
+   @Option(name = "--value", description = "value to use in the filter.")
+   private String value;
+
+   @Option(name = "--maxRows", description = "max number of queues displayed. Default is 50.")
+   private int maxRows = 50;
+
+   //easier for testing
+   public void setQueueName(String queueName) {
+      this.queueName = queueName;
+   }
+
+   public void setOperationName(String operationName) {
+      this.operationName = operationName;
+   }
+
+   public void setFieldName(String fieldName) {
+      this.fieldName = fieldName;
+   }
+
+   public void setValue(String value) {
+      this.value = value;
+   }
+
+   public void setMaxRows(int maxRows) {
+      this.maxRows = maxRows;
+   }
+
+   public void setUser(String user) {
+      this.user = user;
+   }
+
+   public void setPassword(String password) {
+      this.password = password;
+   }
+
+   public void setverbose(boolean verbose) {
+      this.verbose = verbose;
+   }
+
+   @Override
+   public Object execute(ActionContext context) throws Exception {
+      super.execute(context);
+      String filter = createFilter();
+
+      //should always get an initialised filter back when values correct
+      if (filter == null) {
+         return null;
+      }
+
+      if (verbose) {
+         context.out.println("filter is '" + filter + "'");
+         context.out.println("maxRows='" + maxRows + "'");
+      }
+      printStats(context, filter, maxRows);
+      return null;
+   }
+
+   private void printStats(final ActionContext context, final String filter, int maxRows) throws Exception {
+      performCoreManagement(new ManagementCallback<ClientMessage>() {
+         @Override
+         public void setUpInvocation(ClientMessage message) throws Exception {
+            ManagementHelper.putOperationInvocation(message, "broker", "listQueues", filter, 1, maxRows);
+         }
+
+         @Override
+         public void requestSuccessful(ClientMessage reply) throws Exception {
+            final String result = (String) ManagementHelper.getResult(reply, String.class);
+            printStats(result);
+         }
+
+         @Override
+         public void requestFailed(ClientMessage reply) throws Exception {
+            String errMsg = (String) ManagementHelper.getResult(reply, String.class);
+            context.err.println("Failed to get Stats for Queues. Reason: " + errMsg);
+         }
+      });
+   }
+
+   private void printStats(String result) {
+      printHeadings();
+
+      //should not happen but...
+      if (result == null) {
+         if (verbose) {
+            context.err.println("printStats(): got NULL result string.");
+         }
+         return;
+      }
+
+      JsonObject queuesAsJsonObject = JsonUtil.readJsonObject(result);
+      JsonArray array = (JsonArray) queuesAsJsonObject.get("data");
+
+      for (int i = 0; i < array.size(); i++) {
+         printQueueStats(array.getJsonObject(i));
+      }
+   }
+
+   private void printHeadings() {
+
+      StringBuilder stringBuilder = new StringBuilder(134).append('|').append(paddingString(new StringBuilder(FIELD.NAME.toString()), 25)).append('|').append(paddingString(new StringBuilder(FIELD.ADDRESS.toString()), 25)).append('|').append(paddingString(new StringBuilder(FIELD.CONSUMER_COUNT.toString() + " "), 15)).append('|').append(paddingString(new StringBuilder(FIELD.MESSAGE_COUNT.toString() + " "), 14)).append('|').append(paddingString(new StringBuilder(FIELD.MESSAGES_ADDED.toString() + " "), 15)).append('|').append(paddingString(new StringBuilder(FIELD.DELIVERING_COUNT.toString() + " "), 17)).append('|').append(paddingString(new StringBuilder(FIELD.MESSAGES_ACKED.toString() + " "), 15)).append('|');
+
+      context.out.println(stringBuilder);
+   }
+
+   private void printQueueStats(JsonObject jsonObject) {
+
+      //should not happen but just in case..
+      if (jsonObject == null) {
+         if (verbose) {
+            context.err.println("printQueueStats(): jsonObject is null");
+         }
+         return;
+      }
+
+      StringBuilder stringBuilder = new StringBuilder(134).append('|').append(paddingString(new StringBuilder(jsonObject.getString(FIELD.NAME.getJsonId())), 25)).append('|').append(paddingString(new StringBuilder(jsonObject.getString(FIELD.ADDRESS.getJsonId())), 25)).append('|').append(paddingString(new StringBuilder(jsonObject.getString(FIELD.CONSUMER_COUNT.getJsonId())), 15)).append('|').append(paddingString(new StringBuilder(jsonObject.getString(FIELD.MESSAGE_COUNT.getJsonId())), 14)).append('|').append(paddingString(new StringBuilder(jsonObject.getString(FIELD.MESSAGES_ADDED.getJsonId())), 15)).append('|').append(paddingString(new StringBuilder(jsonObject.getString(FIELD.DELIVERING_COUNT.getJsonId())), 17)).append('|').append(paddingString(new StringBuilder(jsonObject.getString(FIELD.MESSAGES_ACKED.getJsonId())), 15)).append('|');
+
+      context.out.println(stringBuilder);
+   }
+
+   private StringBuilder paddingString(StringBuilder value, int size) {
+
+      //should not happen but just in case ...
+      if (value == null) {
+         return new StringBuilder(size);
+      }
+
+      //would expect to have some data
+      if (value.length() == 0) {
+         value.append("NO DATA");
+      }
+
+      int length = value.length();
+      if (length >= size) {
+         //no padding required
+         return value;
+      }
+
+      for (int i = 1; (i + length) <= size; i++) {
+         value.append(' ');
+      }
+
+      return value;
+   }
+
+   //creates filter used for listQueues()
+   private String createFilter() {
+
+      HashMap<String, Object> filterMap = new HashMap<>();
+
+      if (((fieldName != null) && (fieldName.trim().length() > 0)) && ((queueName != null && queueName.trim().length() > 0))) {
+         context.err.println("'--field' and '--queueName' cannot be specified together.");
+         return null;
+      }
+
+      if ((fieldName != null) && (fieldName.trim().length() > 0)) {
+         try {
+            FIELD field = FIELD.valueOf(fieldName);
+            filterMap.put("field", field.toString());
+         } catch (IllegalArgumentException ex) {
+            context.err.println("'--field' must be set to one of the following " + Arrays.toString(FIELD.values()));
+            return null;
+         }
+
+         //full filter being set ensure value is set
+         if (value == null || value.trim().length() == 0) {
+            context.err.println("'--value' needs to be set when '--field' is specified");
+            return null;
+         }
+         filterMap.put("value", value);
+
+         if (operationName == null) {
+            context.err.println("'--operation' must be set when '--field' is specified " + Arrays.toString(OPERATION.values()));
+            return null;
+         }
+
+         try {
+            OPERATION operation = OPERATION.valueOf(operationName);
+            filterMap.put("operation", operation.toString());
+         } catch (IllegalArgumentException ex) {
+            context.err.println("'--operation' must be set to one of the following " + Arrays.toString(OPERATION.values()));
+            return null;
+         }
+
+      } else if (queueName != null && queueName.trim().length() > 0) {
+         filterMap.put("field", FIELD.NAME.toString());
+         filterMap.put("value", queueName);
+         filterMap.put("operation", OPERATION.CONTAINS.toString());
+      } else {
+         filterMap.put("field", "");
+         filterMap.put("value", "");
+         filterMap.put("operation", "");
+      }
+
+      JsonObject filterJsonObject = JsonUtil.toJsonObject(filterMap);
+      return filterJsonObject.toString();
+   }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/87b570f7/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
----------------------------------------------------------------------
diff --git a/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java b/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
index 8b4098a..bb2ab5a 100644
--- a/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
+++ b/artemis-cli/src/test/java/org/apache/activemq/cli/test/ArtemisTest.java
@@ -17,15 +17,22 @@
 package org.apache.activemq.cli.test;
 
 import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
 import javax.jms.MessageProducer;
 import javax.jms.Session;
 import javax.jms.TextMessage;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.nio.file.Files;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
@@ -38,6 +45,7 @@ import org.apache.activemq.artemis.cli.CLIException;
 import org.apache.activemq.artemis.cli.commands.ActionContext;
 import org.apache.activemq.artemis.cli.commands.Create;
 import org.apache.activemq.artemis.cli.commands.Mask;
+import org.apache.activemq.artemis.cli.commands.queue.StatQueue;
 import org.apache.activemq.artemis.cli.commands.Run;
 import org.apache.activemq.artemis.cli.commands.user.AddUser;
 import org.apache.activemq.artemis.cli.commands.user.ListUser;
@@ -630,6 +638,341 @@ public class ArtemisTest extends CliTestBase {
 
    }
 
+   @Test
+   public void testQstat() throws Exception {
+
+      File instanceQstat = new File(temporaryFolder.getRoot(), "instanceQStat");
+      setupAuth(instanceQstat);
+      Run.setEmbedded(true);
+      Artemis.main("create", instanceQstat.getAbsolutePath(), "--silent", "--no-fsync", "--no-autotune", "--no-web", "--require-login");
+      System.setProperty("artemis.instance", instanceQstat.getAbsolutePath());
+      Artemis.internalExecute("run");
+
+      try (ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("tcp://localhost:61616"); Connection connection = cf.createConnection("admin", "admin");) {
+
+         //set up some queues with messages and consumers
+         Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         connection.start();
+         sendMessages(session, "Test1", 15);
+         sendMessages(session, "Test11", 1);
+         sendMessages(session, "Test12", 1);
+         sendMessages(session, "Test20", 20);
+         MessageConsumer consumer = session.createConsumer(ActiveMQDestination.createDestination("queue://Test1", ActiveMQDestination.TYPE.QUEUE));
+         MessageConsumer consumer2 = session.createConsumer(ActiveMQDestination.createDestination("queue://Test1", ActiveMQDestination.TYPE.QUEUE));
+
+         for (int i = 0; i < 5; i++) {
+            Message message = consumer.receive(100);
+         }
+
+         //check all queues containing "Test1" are displayed
+         TestActionContext context = new TestActionContext();
+         StatQueue statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setQueueName("Test1");
+         statQueue.execute(context);
+         ArrayList<String> lines = getOutputLines(context, false);
+         // Header line + 3 queues
+         Assert.assertEquals("rows returned using queueName=Test1", 4, lines.size());
+
+         //check all queues are displayed when no Filter set
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         // Header line + 4 queues (at least - possibly other infra queues as well)
+         Assert.assertTrue("rows returned filtering no name ", 5 <= lines.size());
+
+         //check all queues containing "Test1" are displayed using Filter field NAME
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setFieldName("NAME");
+         statQueue.setOperationName("CONTAINS");
+         statQueue.setValue("Test1");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         // Header line + 3 queues
+         Assert.assertEquals("rows returned filtering by NAME ", 4, lines.size());
+
+         //check only queue named "Test1" is displayed using Filter field NAME and operation EQUALS
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setFieldName("NAME");
+         statQueue.setOperationName("EQUALS");
+         statQueue.setValue("Test1");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         //Header line + 1 queue only
+         Assert.assertEquals("rows returned filtering by NAME operation EQUALS", 2, lines.size());
+         //verify contents of queue stat line is correct
+         String queueTest1 = lines.get(1);
+         String[] parts = queueTest1.split("\\|");
+         Assert.assertEquals("queue name", "Test1", parts[1].trim());
+         Assert.assertEquals("address name", "Test1", parts[2].trim());
+         Assert.assertEquals("Consumer count", "2", parts[3].trim());
+         Assert.assertEquals("Message count", "10", parts[4].trim());
+         Assert.assertEquals("Added count", "15", parts[5].trim());
+         Assert.assertEquals("Delivering count", "10", parts[6].trim());
+         Assert.assertEquals("Acked count", "5", parts[7].trim());
+
+         //check all queues containing address "Test1" are displayed using Filter field ADDRESS
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setFieldName("ADDRESS");
+         statQueue.setOperationName("CONTAINS");
+         statQueue.setValue("Test1");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         // Header line + 3 queues
+         Assert.assertEquals("rows returned filtering by ADDRESS", 4, lines.size());
+
+         //check all queues containing address "Test1" are displayed using Filter field MESSAGE_COUNT
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setFieldName("MESSAGE_COUNT");
+         statQueue.setOperationName("CONTAINS");
+         statQueue.setValue("10");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+
+         // Header line + 1 queues
+         Assert.assertEquals("rows returned filtering by MESSAGE_COUNT", 2, lines.size());
+         String[] columns = lines.get(1).split("\\|");
+         Assert.assertEquals("queue name filtering by MESSAGE_COUNT ", "Test1", columns[2].trim());
+
+         //check all queues containing address "Test1" are displayed using Filter field MESSAGE_ADDED
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setFieldName("MESSAGES_ADDED");
+         statQueue.setOperationName("CONTAINS");
+         statQueue.setValue("20");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         // Header line + 1 queues
+         Assert.assertEquals("rows returned filtering by MESSAGES_ADDED", 2, lines.size());
+         columns = lines.get(1).split("\\|");
+         Assert.assertEquals("queue name filtered by MESSAGE_ADDED", "Test20", columns[2].trim());
+
+         //check all queues containing address "Test1" are displayed using Filter field DELIVERING_COUNT
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setFieldName("DELIVERING_COUNT");
+         statQueue.setOperationName("EQUALS");
+         statQueue.setValue("10");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         columns = lines.get(1).split("\\|");
+         // Header line + 1 queues
+         Assert.assertEquals("rows returned filtering by DELIVERING_COUNT", 2, lines.size());
+         Assert.assertEquals("queue name filtered by DELIVERING_COUNT ", "Test1", columns[2].trim());
+
+         //check all queues containing address "Test1" are displayed using Filter field CONSUMER_COUNT
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setFieldName("CONSUMER_COUNT");
+         statQueue.setOperationName("EQUALS");
+         statQueue.setValue("2");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         columns = lines.get(1).split("\\|");
+         // Header line + 1 queues
+         Assert.assertEquals("rows returned filtering by CONSUMER_COUNT ", 2, lines.size());
+         Assert.assertEquals("queue name filtered by CONSUMER_COUNT ", "Test1", columns[2].trim());
+
+         //check all queues containing address "Test1" are displayed using Filter field MESSAGE_ACKED
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setFieldName("MESSAGES_ACKED");
+         statQueue.setOperationName("EQUALS");
+         statQueue.setValue("5");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         columns = lines.get(1).split("\\|");
+         // Header line + 1 queues
+         Assert.assertEquals("rows returned filtering by MESSAGE_ACKED ", 2, lines.size());
+         Assert.assertEquals("queue name filtered by MESSAGE_ACKED", "Test1", columns[2].trim());
+
+         //check no queues  are displayed when name does not match
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setQueueName("no_queue_name");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         // Header line + 0 queues
+         Assert.assertEquals("rows returned by queueName for no Matching queue ", 1, lines.size());
+
+         //check maxrows is taking effect"
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setQueueName("Test1");
+         statQueue.setMaxRows(1);
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         // Header line + 1 queue only
+         Assert.assertEquals("rows returned by maxRows=1", 2, lines.size());
+
+      } finally {
+         stopServer();
+      }
+
+   }
+
+   @Test
+   public void testQstatErrors() throws Exception {
+
+      File instanceQstat = new File(temporaryFolder.getRoot(), "instanceQStatErrors");
+      setupAuth(instanceQstat);
+      Run.setEmbedded(true);
+      Artemis.main("create", instanceQstat.getAbsolutePath(), "--silent", "--no-fsync", "--no-autotune", "--no-web", "--require-login");
+      System.setProperty("artemis.instance", instanceQstat.getAbsolutePath());
+      Artemis.internalExecute("run");
+      try {
+
+         //check err when FIELD wrong"
+         TestActionContext context = new TestActionContext();
+         StatQueue statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setFieldName("WRONG_FILE");
+         statQueue.setOperationName("EQUALS");
+         statQueue.setValue("5");
+         statQueue.execute(context);
+         ArrayList<String> lines = getOutputLines(context, false);
+         // Header line + 0 queue
+         Assert.assertEquals("No stdout for wrong FIELD", 0, lines.size());
+
+         lines = getOutputLines(context, true);
+         // 1 error line
+         Assert.assertEquals("stderr for wrong FIELD", 1, lines.size());
+         Assert.assertTrue("'FIELD incorrect' error messsage", lines.get(0).contains("'--field' must be set to one of the following"));
+
+         //Test err when OPERATION wrong
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setFieldName("MESSAGE_COUNT");
+         statQueue.setOperationName("WRONG_OPERATION");
+         statQueue.setValue("5");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         // Header line + 0 queue
+         Assert.assertEquals("No stdout for wrong OPERATION", 0, lines.size());
+
+         lines = getOutputLines(context, true);
+         // 1 error line
+         Assert.assertEquals("stderr for wrong OPERATION", 1, lines.size());
+         Assert.assertTrue("'OPERATION incorrect' error message", lines.get(0).contains("'--operation' must be set to one of the following"));
+
+         //Test err when queueName and field set together
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setQueueName("DLQ");
+         statQueue.setFieldName("MESSAGE_COUNT");
+         statQueue.setOperationName("CONTAINS");
+         statQueue.setValue("5");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         // Header line + 0 queue
+         Assert.assertEquals("No stdout for --field and --queueName both set", 0, lines.size());
+
+         lines = getOutputLines(context, true);
+         // 1 error line
+         Assert.assertEquals("stderr for  --field and --queueName both set", 1, lines.size());
+         Assert.assertTrue("field and queueName error message", lines.get(0).contains("'--field' and '--queueName' cannot be specified together"));
+
+         //Test err when field set but no value
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setFieldName("MESSAGE_COUNT");
+         statQueue.setOperationName("CONTAINS");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         // Header line + 0 queue
+         Assert.assertEquals("No stdout for --field set BUT no --value", 0, lines.size());
+         lines = getOutputLines(context, true);
+         // 1 error line
+         Assert.assertEquals("stderr for --field set BUT no --value", 1, lines.size());
+         Assert.assertTrue("NO VALUE error message", lines.get(0).contains("'--value' needs to be set when '--field' is specified"));
+
+         //Test err when field set but no operation
+         context = new TestActionContext();
+         statQueue = new StatQueue();
+         statQueue.setUser("admin");
+         statQueue.setPassword("admin");
+         statQueue.setFieldName("MESSAGE_COUNT");
+         statQueue.setValue("5");
+         statQueue.execute(context);
+         lines = getOutputLines(context, false);
+         // Header line + 0 queue
+         Assert.assertEquals("No stdout for --field set BUT no --operation", 0, lines.size());
+         lines = getOutputLines(context, true);
+         // 1 error line
+         Assert.assertEquals("stderr for --field set BUT no --operation", 1, lines.size());
+         Assert.assertTrue("OPERATION incorrect error message", lines.get(0).contains("'--operation' must be set when '--field' is specified "));
+
+      } finally {
+         stopServer();
+      }
+
+   }
+
+   //read individual lines from byteStream
+   private ArrayList<String> getOutputLines(TestActionContext context, boolean errorOutput) throws IOException {
+      byte[] bytes;
+
+      if (errorOutput) {
+         bytes = context.getStdErrBytes();
+      } else {
+         bytes = context.getStdoutBytes();
+      }
+      BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes)));
+      ArrayList<String> lines = new ArrayList<>();
+
+      String currentLine = bufferedReader.readLine();
+      while (currentLine != null) {
+         lines.add(currentLine);
+         currentLine = bufferedReader.readLine();
+      }
+
+      return lines;
+   }
+
+   private void sendMessages(Session session, String queueName, int messageCount) throws JMSException {
+      MessageProducer producer = session.createProducer(ActiveMQDestination.createDestination("queue://" + queueName, ActiveMQDestination.TYPE.QUEUE));
+
+      TextMessage message = session.createTextMessage("sample message");
+      for (int i = 0; i < messageCount; i++) {
+         producer.send(message);
+      }
+   }
+
    private void testCli(String... args) {
       try {
          Artemis.main(args);

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/87b570f7/artemis-cli/src/test/java/org/apache/activemq/cli/test/TestActionContext.java
----------------------------------------------------------------------
diff --git a/artemis-cli/src/test/java/org/apache/activemq/cli/test/TestActionContext.java b/artemis-cli/src/test/java/org/apache/activemq/cli/test/TestActionContext.java
index 0a2da11..9a41fa6 100644
--- a/artemis-cli/src/test/java/org/apache/activemq/cli/test/TestActionContext.java
+++ b/artemis-cli/src/test/java/org/apache/activemq/cli/test/TestActionContext.java
@@ -44,7 +44,15 @@ public class TestActionContext extends ActionContext {
       return stdout.toString();
    }
 
+   public byte[] getStdoutBytes() {
+      return stdout.toByteArray();
+   }
+
    public String getStderr() {
       return stderr.toString();
    }
+
+   public byte[] getStdErrBytes() {
+      return stderr.toByteArray();
+   }
 }