You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by pr...@apache.org on 2018/05/23 18:05:46 UTC
[geode] branch develop updated: GEODE-4858: Refactor 'list
async-event-queue' command and function (#1975)
This is an automated email from the ASF dual-hosted git repository.
prhomberg pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push:
new 2faf3fb GEODE-4858: Refactor 'list async-event-queue' command and function (#1975)
2faf3fb is described below
commit 2faf3fb7756109a27359f68de258164352709c40
Author: Patrick Rhomberg <pr...@pivotal.io>
AuthorDate: Wed May 23 11:05:41 2018 -0700
GEODE-4858: Refactor 'list async-event-queue' command and function (#1975)
* Command refactored for cleaner presentation
* Command refactored to return ResultModel
* Function refactored to extend CliFunction
---
.../cli/commands/ListAsyncEventQueuesCommand.java | 143 +++++------
.../cli/domain/AsyncEventQueueDetails.java | 6 +-
.../functions/ListAsyncEventQueuesFunction.java | 71 ++----
.../ListAsyncEventQueuesCommandDUnitTest.java | 7 +-
.../cli/commands/ListAsyncEventQueuesTest.java | 264 +++++++++++++++++++++
.../test/junit/assertions/CommandResultAssert.java | 6 +-
6 files changed, 368 insertions(+), 129 deletions(-)
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListAsyncEventQueuesCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListAsyncEventQueuesCommand.java
index 55fe663..c414307 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListAsyncEventQueuesCommand.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListAsyncEventQueuesCommand.java
@@ -15,104 +15,105 @@
package org.apache.geode.management.internal.cli.commands;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.util.List;
-import java.util.Map;
import java.util.Properties;
import java.util.Set;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.shell.core.annotation.CliCommand;
-import org.apache.geode.SystemFailure;
-import org.apache.geode.cache.execute.ResultCollector;
import org.apache.geode.distributed.DistributedMember;
-import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.CliUtil;
import org.apache.geode.management.internal.cli.domain.AsyncEventQueueDetails;
import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
import org.apache.geode.management.internal.cli.functions.ListAsyncEventQueuesFunction;
import org.apache.geode.management.internal.cli.i18n.CliStrings;
-import org.apache.geode.management.internal.cli.result.ResultBuilder;
-import org.apache.geode.management.internal.cli.result.TabularResultData;
+import org.apache.geode.management.internal.cli.result.model.ResultModel;
+import org.apache.geode.management.internal.cli.result.model.TabularResultModel;
import org.apache.geode.management.internal.security.ResourceOperation;
import org.apache.geode.security.ResourcePermission;
public class ListAsyncEventQueuesCommand extends InternalGfshCommand {
+ private static final String[] DETAILS_OUTPUT_COLUMNS =
+ {"Member", "ID", "Batch Size", "Persistent", "Disk Store", "Max Memory", "Listener"};
+ private static final String ASYNC_EVENT_QUEUES_TABLE_SECTION = "Async Event Queues";
+ private static final String MEMBER_ERRORS_TABLE_SECTION = "Member Errors";
+
@CliCommand(value = CliStrings.LIST_ASYNC_EVENT_QUEUES,
help = CliStrings.LIST_ASYNC_EVENT_QUEUES__HELP)
@ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
operation = ResourcePermission.Operation.READ)
- public Result listAsyncEventQueues() {
- try {
- TabularResultData tabularData = ResultBuilder.createTabularResultData();
- boolean accumulatedData = false;
+ public ResultModel listAsyncEventQueues() {
+ Set<DistributedMember> targetMembers = getAllNormalMembers();
+ if (targetMembers.isEmpty()) {
+ return ResultModel.createError(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
+ }
- Set<DistributedMember> targetMembers = getAllNormalMembers();
+ // Each (successful) member returns a list of AsyncEventQueueDetails.
+ List<CliFunctionResult> results = executeAndGetFunctionResult(
+ new ListAsyncEventQueuesFunction(), new Object[] {}, targetMembers);
- if (targetMembers.isEmpty()) {
- return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
- }
+ ResultModel result = buildAsyncEventQueueInfo(results);
- ResultCollector<?, ?> rc = CliUtil.executeFunction(new ListAsyncEventQueuesFunction(),
- new Object[] {}, targetMembers);
- List<CliFunctionResult> results = CliFunctionResult.cleanResults((List<?>) rc.getResult());
+ // Report any explicit errors as well.
+ if (results.stream().anyMatch(r -> !r.isSuccessful())) {
+ TabularResultModel errors = result.addTable(MEMBER_ERRORS_TABLE_SECTION);
+ errors.setColumnHeader("Member", "Error");
+ results.stream().filter(r -> !r.isSuccessful()).forEach(errorResult -> errors
+ .addRow(errorResult.getMemberIdOrName(), errorResult.getStatusMessage()));
+ }
- for (CliFunctionResult result : results) {
- if (result.getThrowable() != null) {
- tabularData.accumulate("Member", result.getMemberIdOrName());
- tabularData.accumulate("Result", "ERROR: " + result.getThrowable().getClass().getName()
- + ": " + result.getThrowable().getMessage());
- accumulatedData = true;
- tabularData.setStatus(Result.Status.ERROR);
- } else {
- AsyncEventQueueDetails[] details = (AsyncEventQueueDetails[]) result.getSerializables();
- for (AsyncEventQueueDetails detail : details) {
- tabularData.accumulate("Member", result.getMemberIdOrName());
- tabularData.accumulate("ID", detail.getId());
- tabularData.accumulate("Batch Size", detail.getBatchSize());
- tabularData.accumulate("Persistent", detail.isPersistent());
- tabularData.accumulate("Disk Store", detail.getDiskStoreName());
- tabularData.accumulate("Max Memory", detail.getMaxQueueMemory());
+ return result;
+ }
- Properties listenerProperties = detail.getListenerProperties();
- if (listenerProperties == null || listenerProperties.size() == 0) {
- tabularData.accumulate("Listener", detail.getListener());
- } else {
- StringBuilder propsStringBuilder = new StringBuilder();
- propsStringBuilder.append('(');
- boolean firstProperty = true;
- for (Map.Entry<Object, Object> property : listenerProperties.entrySet()) {
- if (!firstProperty) {
- propsStringBuilder.append(',');
- } else {
- firstProperty = false;
- }
- propsStringBuilder.append(property.getKey()).append('=')
- .append(property.getValue());
- }
- propsStringBuilder.append(')');
+ /**
+ * @return An info result containing the table of AsyncEventQueueDetails.
+ * If no details are found, returns an info result message indicating so.
+ */
+ private ResultModel buildAsyncEventQueueInfo(List<CliFunctionResult> results) {
+ if (results.stream().filter(CliFunctionResult::isSuccessful)
+ .noneMatch(r -> ((List<AsyncEventQueueDetails>) r.getResultObject()).size() > 0)) {
+ return ResultModel.createInfo(CliStrings.LIST_ASYNC_EVENT_QUEUES__NO_QUEUES_FOUND_MESSAGE);
+ }
- tabularData.accumulate("Listener",
- detail.getListener() + propsStringBuilder.toString());
- }
- accumulatedData = true;
- }
- }
- }
+ ResultModel result = new ResultModel();
+ TabularResultModel detailsTable = result.addTable(ASYNC_EVENT_QUEUES_TABLE_SECTION);
+ detailsTable.setColumnHeader(DETAILS_OUTPUT_COLUMNS);
- if (!accumulatedData) {
- return ResultBuilder
- .createInfoResult(CliStrings.LIST_ASYNC_EVENT_QUEUES__NO_QUEUES_FOUND_MESSAGE);
- }
+ results.stream().filter(CliFunctionResult::isSuccessful).forEach(successfulResult -> {
+ String memberName = successfulResult.getMemberIdOrName();
+ ((List<AsyncEventQueueDetails>) successfulResult.getResultObject())
+ .forEach(entry -> detailsTable.addRow(memberName, entry.getId(),
+ String.valueOf(entry.getBatchSize()), String.valueOf(entry.isPersistent()),
+ String.valueOf(entry.getDiskStoreName()), String.valueOf(entry.getMaxQueueMemory()),
+ getListenerEntry(entry)));
+ });
+ return result;
+ }
+
+ /**
+ * @return The class of the entry's listener. If the listener is parameterized, these parameters
+ * are appended in a json format.
+ */
+ private String getListenerEntry(AsyncEventQueueDetails entry) {
+ return entry.getListener() + propertiesToString(entry.getListenerProperties());
+ }
- return ResultBuilder.buildResult(tabularData);
- } catch (VirtualMachineError e) {
- SystemFailure.initiateFailure(e);
- throw e;
- } catch (Throwable th) {
- SystemFailure.checkFailure();
- return ResultBuilder.createGemFireErrorResult(
- CliStrings.format(CliStrings.LIST_ASYNC_EVENT_QUEUES__ERROR_WHILE_LISTING_REASON_0,
- new Object[] {th.getMessage()}));
+ /**
+ * @return A json format of the properties, or the empty string if the properties are empty.
+ */
+ static String propertiesToString(Properties props) {
+ if (props == null || props.isEmpty()) {
+ return "";
+ }
+ ObjectMapper mapper = new ObjectMapper();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ mapper.writeValue(baos, props);
+ } catch (IOException e) {
+ return e.getMessage();
}
+ return baos.toString();
}
}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/AsyncEventQueueDetails.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/AsyncEventQueueDetails.java
index 720fe6f..95f836d 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/AsyncEventQueueDetails.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/domain/AsyncEventQueueDetails.java
@@ -14,15 +14,15 @@
*/
package org.apache.geode.management.internal.cli.domain;
+import java.io.Serializable;
+import java.util.Properties;
+
/**
* Used to transfer information about an AsyncEventQueue from a function being executed on a server
* back to the manager that invoked the function.
*
* @since GemFire 8.0
*/
-import java.io.Serializable;
-import java.util.Properties;
-
public class AsyncEventQueueDetails implements Serializable {
private static final long serialVersionUID = 1L;
private final String id;
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ListAsyncEventQueuesFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ListAsyncEventQueuesFunction.java
index 2bb4a50..b0bd9de 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ListAsyncEventQueuesFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ListAsyncEventQueuesFunction.java
@@ -14,21 +14,18 @@
*/
package org.apache.geode.management.internal.cli.functions;
+import java.util.List;
import java.util.Properties;
import java.util.Set;
+import java.util.stream.Collectors;
-import org.apache.logging.log4j.Logger;
-
-import org.apache.geode.SystemFailure;
import org.apache.geode.cache.Cache;
-import org.apache.geode.cache.CacheClosedException;
import org.apache.geode.cache.asyncqueue.AsyncEventListener;
import org.apache.geode.cache.asyncqueue.AsyncEventQueue;
import org.apache.geode.cache.execute.FunctionContext;
import org.apache.geode.distributed.DistributedMember;
-import org.apache.geode.internal.cache.execute.InternalFunction;
import org.apache.geode.internal.cache.xmlcache.Declarable2;
-import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.management.cli.CliFunction;
import org.apache.geode.management.internal.cli.domain.AsyncEventQueueDetails;
/**
@@ -38,8 +35,7 @@ import org.apache.geode.management.internal.cli.domain.AsyncEventQueueDetails;
*
* @since GemFire 8.0
*/
-public class ListAsyncEventQueuesFunction implements InternalFunction {
- private static final Logger logger = LogService.getLogger();
+public class ListAsyncEventQueuesFunction extends CliFunction {
private static final long serialVersionUID = 1L;
@@ -49,53 +45,26 @@ public class ListAsyncEventQueuesFunction implements InternalFunction {
}
@Override
- public void execute(final FunctionContext context) {
- // Declared here so that it's available when returning a Throwable
- String memberId = "";
-
- try {
- Cache cache = context.getCache();
+ public CliFunctionResult executeFunction(final FunctionContext context) {
+ Cache cache = context.getCache();
+ DistributedMember member = cache.getDistributedSystem().getDistributedMember();
- DistributedMember member = cache.getDistributedSystem().getDistributedMember();
-
- memberId = member.getId();
- // If they set a name use it instead
- if (!member.getName().equals("")) {
- memberId = member.getName();
- }
+ // Identify by name if the name is non-trivial. Otherwise, use the ID
+ String memberId = !member.getName().equals("") ? member.getName() : member.getId();
- Set<AsyncEventQueue> asyncEventQueues = cache.getAsyncEventQueues();
+ Set<AsyncEventQueue> asyncEventQueues = cache.getAsyncEventQueues();
- AsyncEventQueueDetails[] asyncEventQueueDetails =
- new AsyncEventQueueDetails[asyncEventQueues.size()];
- int i = 0;
- for (AsyncEventQueue queue : asyncEventQueues) {
- AsyncEventListener listener = queue.getAsyncEventListener();
- Properties listenerProperties = new Properties();
- if (listener instanceof Declarable2) {
- listenerProperties = ((Declarable2) listener).getConfig();
- }
- asyncEventQueueDetails[i++] = new AsyncEventQueueDetails(queue.getId(),
- queue.getBatchSize(), queue.isPersistent(), queue.getDiskStoreName(),
- queue.getMaximumQueueMemory(), listener.getClass().getName(), listenerProperties);
+ List<AsyncEventQueueDetails> details = asyncEventQueues.stream().map(queue -> {
+ AsyncEventListener listener = queue.getAsyncEventListener();
+ Properties listenerProperties = new Properties();
+ if (listener instanceof Declarable2) {
+ listenerProperties = ((Declarable2) listener).getConfig();
}
+ return new AsyncEventQueueDetails(queue.getId(), queue.getBatchSize(), queue.isPersistent(),
+ queue.getDiskStoreName(), queue.getMaximumQueueMemory(), listener.getClass().getName(),
+ listenerProperties);
+ }).collect(Collectors.toList());
- CliFunctionResult result = new CliFunctionResult(memberId, asyncEventQueueDetails);
- context.getResultSender().lastResult(result);
-
- } catch (CacheClosedException cce) {
- CliFunctionResult result = new CliFunctionResult(memberId, false, null);
- context.getResultSender().lastResult(result);
-
- } catch (VirtualMachineError e) {
- SystemFailure.initiateFailure(e);
- throw e;
-
- } catch (Throwable th) {
- SystemFailure.checkFailure();
- logger.error("Could not list async event queues: {}", th.getMessage(), th);
- CliFunctionResult result = new CliFunctionResult(memberId, th, null);
- context.getResultSender().lastResult(result);
- }
+ return new CliFunctionResult(memberId, details);
}
}
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListAsyncEventQueuesCommandDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListAsyncEventQueuesCommandDUnitTest.java
index 38cea6c..7c6844d 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListAsyncEventQueuesCommandDUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListAsyncEventQueuesCommandDUnitTest.java
@@ -24,6 +24,7 @@ import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.internal.cache.wan.MyAsyncEventListener;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
import org.apache.geode.test.dunit.rules.ClusterStartupRule;
import org.apache.geode.test.dunit.rules.MemberVM;
import org.apache.geode.test.junit.categories.AEQTest;
@@ -43,16 +44,16 @@ public class ListAsyncEventQueuesCommandDUnitTest {
private static MemberVM locator;
@BeforeClass
- public static void beforeClass() throws Exception {
+ public static void beforeClass() {
locator = lsRule.startLocatorVM(0);
lsRule.startServerVM(1, "group1", locator.getPort());
lsRule.startServerVM(2, "group2", locator.getPort());
}
@Test
- public void list() throws Exception {
+ public void list() {
gfsh.executeAndAssertThat("list async-event-queue").statusIsSuccess()
- .containsOutput("No Async Event Queues Found");
+ .containsOutput(CliStrings.LIST_ASYNC_EVENT_QUEUES__NO_QUEUES_FOUND_MESSAGE);
gfsh.executeAndAssertThat("create async-event-queue --id=queue1 --group=group1 --listener="
+ MyAsyncEventListener.class.getName()).statusIsSuccess();
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListAsyncEventQueuesTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListAsyncEventQueuesTest.java
new file mode 100644
index 0000000..a771a57
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ListAsyncEventQueuesTest.java
@@ -0,0 +1,264 @@
+/*
+ * 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.geode.management.internal.cli.commands;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.management.internal.cli.domain.AsyncEventQueueDetails;
+import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.test.junit.categories.AEQTest;
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.apache.geode.test.junit.rules.GfshParserRule;
+
+@Category({UnitTest.class, AEQTest.class})
+public class ListAsyncEventQueuesTest {
+ private static final String COMMAND = "list async-event-queues ";
+
+ @ClassRule
+ public static GfshParserRule gfsh = new GfshParserRule();
+ private static final String FUNCTION_EXCEPTION_MESSAGE =
+ "A mysterious test exception occurred during function execution.";
+
+ private ListAsyncEventQueuesCommand command;
+ private List<CliFunctionResult> memberCliResults;
+ private DistributedMember mockedMember;
+ private DistributedMember anotherMockedMember;
+
+
+ @Before
+ public void before() throws Exception {
+ mockedMember = mock(DistributedMember.class);
+ anotherMockedMember = mock(DistributedMember.class);
+ command = spy(ListAsyncEventQueuesCommand.class);
+ }
+
+ @Test
+ public void noMembersFound() {
+ // Mock zero members
+ doReturn(Collections.emptySet()).when(command).getAllNormalMembers();
+
+ // Command should succeed with one row of data
+ gfsh.executeAndAssertThat(command, COMMAND).statusIsError()
+ .containsOutput(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
+ }
+
+ @Test
+ public void oneServerWithOneQueue() {
+ // Mock one member
+ doReturn(new HashSet<>(Collections.singletonList(mockedMember))).when(command)
+ .getAllNormalMembers();
+
+ // Mock member's queue details
+ FakeDetails details = new FakeDetails("server1", "s1-queue-id", 5, true, "diskStoreName", 10,
+ "my.listener.class", new Properties());
+ CliFunctionResult memberResult = new CliFunctionResult(details.getMemberName(),
+ Collections.singletonList(details.asAsyncEventQueueDetails()));
+ memberCliResults = Collections.singletonList(memberResult);
+ doReturn(memberCliResults).when(command).executeAndGetFunctionResult(any(), any(), any());
+
+ // Command should succeed with one row of data
+ gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess()
+ .tableHasRowWithValues(details.expectedRowHeaderAndValue());
+ }
+
+ @Test
+ public void oneServerWithOneParameterizedQueue() {
+ // Mock one member
+ doReturn(new HashSet<>(Collections.singletonList(mockedMember))).when(command)
+ .getAllNormalMembers();
+
+ // Mock member's queue details
+ Properties listenerProperties = new Properties();
+ listenerProperties.setProperty("special-property", "special-value");
+ listenerProperties.setProperty("another-property", "mundane-value");
+ FakeDetails details = new FakeDetails("server1", "s1-queue-id", 5, true, "diskStoreName", 10,
+ "my.listener.class", listenerProperties);
+ CliFunctionResult memberResult = new CliFunctionResult(details.getMemberName(),
+ Collections.singletonList(details.asAsyncEventQueueDetails()));
+ memberCliResults = Collections.singletonList(memberResult);
+ doReturn(memberCliResults).when(command).executeAndGetFunctionResult(any(), any(), any());
+
+ // Command should succeed with one row of data
+ gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess()
+ .tableHasRowWithValues(details.expectedRowHeaderAndValue());
+ }
+
+ @Test
+ public void oneMemberButNoQueues() {
+ // Mock one member
+ doReturn(new HashSet<>(Collections.singletonList(mockedMember))).when(command)
+ .getAllNormalMembers();
+
+ // Mock member's lack of queue details
+ CliFunctionResult memberResult = new CliFunctionResult("server1", Collections.emptyList());
+ memberCliResults = Collections.singletonList(memberResult);
+ doReturn(memberCliResults).when(command).executeAndGetFunctionResult(any(), any(), any());
+
+ // Command should succeed, but indicate there were no queues
+ gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess()
+ .containsOutput(CliStrings.LIST_ASYNC_EVENT_QUEUES__NO_QUEUES_FOUND_MESSAGE);
+ }
+
+ @Test
+ public void oneMemberWhoErrorsOut() {
+ // Mock one member
+ doReturn(new HashSet<>(Collections.singletonList(mockedMember))).when(command)
+ .getAllNormalMembers();
+
+ // Mock member's error result
+ CliFunctionResult memberResult =
+ new CliFunctionResult("server1", new Exception(FUNCTION_EXCEPTION_MESSAGE));
+ memberCliResults = Collections.singletonList(memberResult);
+ doReturn(memberCliResults).when(command).executeAndGetFunctionResult(any(), any(), any());
+
+ // Command should succeed, but indicate there were no queues
+ gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess()
+ .containsOutput(CliStrings.LIST_ASYNC_EVENT_QUEUES__NO_QUEUES_FOUND_MESSAGE);
+ }
+
+ @Test
+ public void twoServersWithManyQueues() {
+ // Mock two members, even though they're not directly consumed
+ doReturn(new HashSet<>(Arrays.asList(mockedMember, anotherMockedMember))).when(command)
+ .getAllNormalMembers();
+
+ // Mock member's queue details
+ FakeDetails details1 = new FakeDetails("server1", "s1-queue-id1", 5, false, "diskStoreName", 1,
+ "my.listener.class", new Properties());
+ FakeDetails details2 = new FakeDetails("server1", "s1-queue-id2", 15, true,
+ "otherDiskStoreName", 10, "my.listener.class", new Properties());
+ FakeDetails details3 = new FakeDetails("server1", "s1-queue-id3", 25, true, "diskStoreName",
+ 100, "my.listener.class", new Properties());
+ CliFunctionResult member1Result =
+ new CliFunctionResult("server1", Arrays.asList(details1.asAsyncEventQueueDetails(),
+ details2.asAsyncEventQueueDetails(), details3.asAsyncEventQueueDetails()));
+
+ FakeDetails details4 = new FakeDetails("server2", "s2-queue-id1", 5, false, "diskStoreName", 1,
+ "my.listener.class", new Properties());
+ FakeDetails details5 = new FakeDetails("server2", "s2-queue-id2", 15, true,
+ "otherDiskStoreName", 10, "my.listener.class", new Properties());
+ FakeDetails details6 = new FakeDetails("server2", "s2-queue-id3", 25, true, "diskStoreName",
+ 100, "my.listener.class", new Properties());
+ CliFunctionResult member2Result =
+ new CliFunctionResult("server2", Arrays.asList(details4.asAsyncEventQueueDetails(),
+ details5.asAsyncEventQueueDetails(), details6.asAsyncEventQueueDetails()));
+
+ memberCliResults = Arrays.asList(member1Result, member2Result);
+ doReturn(memberCliResults).when(command).executeAndGetFunctionResult(any(), any(), any());
+
+ // Command should succeed with one row of data
+ gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess()
+ .tableHasRowWithValues(details1.expectedRowHeaderAndValue())
+ .tableHasRowWithValues(details2.expectedRowHeaderAndValue())
+ .tableHasRowWithValues(details3.expectedRowHeaderAndValue())
+ .tableHasRowWithValues(details4.expectedRowHeaderAndValue())
+ .tableHasRowWithValues(details5.expectedRowHeaderAndValue())
+ .tableHasRowWithValues(details6.expectedRowHeaderAndValue());
+ }
+
+ @Test
+ public void oneMemberSucceedsAndOneFails() {
+ // Mock two members, even though they're not directly consumed
+ doReturn(new HashSet<>(Arrays.asList(mockedMember, anotherMockedMember))).when(command)
+ .getAllNormalMembers();
+
+ // Mock member's queue details
+ FakeDetails details1 = new FakeDetails("server1", "s1-queue-id1", 5, false, "diskStoreName", 1,
+ "my.listener.class", new Properties());
+ FakeDetails details2 = new FakeDetails("server1", "s1-queue-id2", 15, true,
+ "otherDiskStoreName", 10, "my.listener.class", new Properties());
+ FakeDetails details3 = new FakeDetails("server1", "s1-queue-id3", 25, true, "diskStoreName",
+ 100, "my.listener.class", new Properties());
+ CliFunctionResult member1Result =
+ new CliFunctionResult("server1", Arrays.asList(details1.asAsyncEventQueueDetails(),
+ details2.asAsyncEventQueueDetails(), details3.asAsyncEventQueueDetails()));
+
+ // Mock the other's failure
+ CliFunctionResult member2Result =
+ new CliFunctionResult("server2", new Exception(FUNCTION_EXCEPTION_MESSAGE));
+
+ memberCliResults = Arrays.asList(member1Result, member2Result);
+ doReturn(memberCliResults).when(command).executeAndGetFunctionResult(any(), any(), any());
+
+ // Command should succeed with one row of data
+ gfsh.executeAndAssertThat(command, COMMAND).statusIsSuccess()
+ .tableHasRowWithValues(details1.expectedRowHeaderAndValue())
+ .tableHasRowWithValues(details2.expectedRowHeaderAndValue())
+ .tableHasRowWithValues(details3.expectedRowHeaderAndValue())
+ .containsOutput(FUNCTION_EXCEPTION_MESSAGE);
+ }
+
+ /**
+ * Wrapper for mocked AsyncEventQueueData, with convenience method for expected table output.
+ */
+ class FakeDetails {
+ private String memberName;
+ private String queueId;
+ private int batchSize;
+ private boolean persistent;
+ private String diskStoreName;
+ private int maxQueueMemory;
+ private String listener;
+ private Properties listenerProperties;
+
+ private FakeDetails(String memberName, String queueId, int batchSize, boolean persistent,
+ String diskStoreName, int maxQueueMemory, String listener, Properties listenerProperties) {
+ this.memberName = memberName;
+ this.queueId = queueId;
+ this.batchSize = batchSize;
+ this.persistent = persistent;
+ this.diskStoreName = diskStoreName;
+ this.maxQueueMemory = maxQueueMemory;
+ this.listener = listener;
+ this.listenerProperties = listenerProperties;
+ }
+
+ public String getMemberName() {
+ return memberName;
+ }
+
+ private AsyncEventQueueDetails asAsyncEventQueueDetails() {
+ return new AsyncEventQueueDetails(queueId, batchSize, persistent, diskStoreName,
+ maxQueueMemory, listener, listenerProperties);
+ }
+
+ private String[] expectedRowHeaderAndValue() {
+ return new String[] {"Member", "ID", "Batch Size", "Persistent", "Disk Store", "Max Memory",
+ "Listener", memberName, queueId, String.valueOf(batchSize), String.valueOf(persistent),
+ diskStoreName, String.valueOf(maxQueueMemory), expectedListenerOutput()};
+ }
+
+ private String expectedListenerOutput() {
+ return listener + ListAsyncEventQueuesCommand.propertiesToString(listenerProperties);
+ }
+ }
+}
diff --git a/geode-core/src/test/java/org/apache/geode/test/junit/assertions/CommandResultAssert.java b/geode-core/src/test/java/org/apache/geode/test/junit/assertions/CommandResultAssert.java
index 7528c0b..cb25cbc 100644
--- a/geode-core/src/test/java/org/apache/geode/test/junit/assertions/CommandResultAssert.java
+++ b/geode-core/src/test/java/org/apache/geode/test/junit/assertions/CommandResultAssert.java
@@ -21,6 +21,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.apache.commons.lang.StringUtils;
import org.assertj.core.api.AbstractAssert;
import org.assertj.core.api.Assertions;
import org.json.JSONArray;
@@ -217,7 +218,10 @@ public class CommandResultAssert
}
// did not find any matching rows, then this would pass only if we do not pass in any values
- assertThat(headersThenValues.length).describedAs("No matching row found.").isEqualTo(0);
+ assertThat(headersThenValues.length)
+ .describedAs("No matching row found containing expected values: "
+ + StringUtils.join(expectedValues, ","))
+ .isEqualTo(0);
return this;
}
--
To stop receiving notification emails like this one, please contact
prhomberg@apache.org.