[
https://issues.apache.org/jira/browse/GEODE-7954?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17095430#comment-17095430
]
ASF GitHub Bot commented on GEODE-7954:
---------------------------------------
jujoramos commented on a change in pull request #5004:
URL: https://github.com/apache/geode/pull/5004#discussion_r417251767
##########
File path:
geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/functions/RedundancyCommandFunctionTest.java
##########
@@ -0,0 +1,137 @@
+/*
+ * 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.functions;
+
+import static
org.apache.geode.management.internal.functions.CliFunctionResult.StatusState.ERROR;
+import static
org.apache.geode.management.internal.functions.CliFunctionResult.StatusState.OK;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.control.RestoreRedundancyOperation;
+import org.apache.geode.cache.control.RestoreRedundancyResults;
+import org.apache.geode.cache.execute.FunctionContext;
+import org.apache.geode.management.internal.functions.CliFunctionResult;
+
+public class RedundancyCommandFunctionTest {
+
+ @SuppressWarnings("unchecked")
+ private FunctionContext<Object[]> mockContext = mock(FunctionContext.class);
+ private Cache mockCache = mock(Cache.class, RETURNS_DEEP_STUBS);
+ private RestoreRedundancyOperation mockOperation =
+ mock(RestoreRedundancyOperation.class, RETURNS_DEEP_STUBS);
+ private RestoreRedundancyResults mockResults =
mock(RestoreRedundancyResults.class);
+ private String message = "expected message";
Review comment:
These attributes can all be made `final`.
##########
File path:
geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/StatusRedundancyCommandTest.java
##########
@@ -0,0 +1,253 @@
+/*
+ * 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.apache.geode.management.cli.Result.Status.ERROR;
+import static org.apache.geode.management.cli.Result.Status.OK;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.REDUNDANCY_COMMAND_ADDED_VERSION;
+import static org.hamcrest.CoreMatchers.everyItem;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.internal.functions.CliFunctionResult;
+import
org.apache.geode.management.internal.operation.RebalanceOperationPerformer;
+
+public class StatusRedundancyCommandTest {
+
+ private StatusRedundancyCommand command;
+ private final String includeRegion1 = "include1";
+ private final String includeRegion2 = "include2";
+ private String[] includeRegions = {includeRegion1, includeRegion2};
Review comment:
This field can be made `final`.
##########
File path:
geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/StatusRedundancyCommandTest.java
##########
@@ -0,0 +1,253 @@
+/*
+ * 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.apache.geode.management.cli.Result.Status.ERROR;
+import static org.apache.geode.management.cli.Result.Status.OK;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.REDUNDANCY_COMMAND_ADDED_VERSION;
+import static org.hamcrest.CoreMatchers.everyItem;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.internal.functions.CliFunctionResult;
+import
org.apache.geode.management.internal.operation.RebalanceOperationPerformer;
+
+public class StatusRedundancyCommandTest {
+
+ private StatusRedundancyCommand command;
+ private final String includeRegion1 = "include1";
+ private final String includeRegion2 = "include2";
+ private String[] includeRegions = {includeRegion1, includeRegion2};
+ private final String excludeRegion1 = "exclude1";
+ private final String excludeRegion2 = "exclude2";
+ private String[] excludeRegions = {excludeRegion1, excludeRegion2};
Review comment:
This field can be made `final`.
##########
File path:
geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/RestoreRedundancyCommand.java
##########
@@ -0,0 +1,128 @@
+/*
+ * 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.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.REDUNDANCY_COMMAND_ADDED_VERSION;
+import static
org.apache.geode.management.internal.functions.CliFunctionResult.StatusState.ERROR;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.GfshCommand;
+import
org.apache.geode.management.internal.cli.functions.RedundancyCommandFunction;
+import org.apache.geode.management.internal.cli.result.model.ResultModel;
+import org.apache.geode.management.internal.functions.CliFunctionResult;
+import org.apache.geode.management.internal.i18n.CliStrings;
+import
org.apache.geode.management.internal.operation.RebalanceOperationPerformer;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class RestoreRedundancyCommand extends GfshCommand {
+ static final String COMMAND_NAME = "restore redundancy";
+ private static final String COMMAND_HELP =
+ "Restore redundancy and optionally reassign primary bucket hosting for
partitioned regions in connected members. The default is for all regions to
have redundancy restored and for primary buckets to be reassigned for better
load balance.";
+ static final String INCLUDE_REGION = "include-region";
+ private static final String INCLUDE_REGION_HELP =
+ "Partitioned regions to be included when restoring redundancy. If a
colocated region is included, all regions colocated with that region will also
be included automatically. Includes take precedence over excludes.";
+ static final String EXCLUDE_REGION = "exclude-region";
Review comment:
Maybe use `regions` instead of `region`?.
##########
File path:
geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/RestoreRedundancyCommand.java
##########
@@ -0,0 +1,128 @@
+/*
+ * 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.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.REDUNDANCY_COMMAND_ADDED_VERSION;
+import static
org.apache.geode.management.internal.functions.CliFunctionResult.StatusState.ERROR;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.GfshCommand;
+import
org.apache.geode.management.internal.cli.functions.RedundancyCommandFunction;
+import org.apache.geode.management.internal.cli.result.model.ResultModel;
+import org.apache.geode.management.internal.functions.CliFunctionResult;
+import org.apache.geode.management.internal.i18n.CliStrings;
+import
org.apache.geode.management.internal.operation.RebalanceOperationPerformer;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class RestoreRedundancyCommand extends GfshCommand {
+ static final String COMMAND_NAME = "restore redundancy";
+ private static final String COMMAND_HELP =
+ "Restore redundancy and optionally reassign primary bucket hosting for
partitioned regions in connected members. The default is for all regions to
have redundancy restored and for primary buckets to be reassigned for better
load balance.";
+ static final String INCLUDE_REGION = "include-region";
Review comment:
Maybe use `regions` instead of `region`?.
##########
File path:
geode-gfsh/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/RestoreRedundancyCommandDUnitTest.java
##########
@@ -0,0 +1,618 @@
+/*
+ * 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.apache.geode.cache.PartitionAttributesFactory.GLOBAL_MAX_BUCKETS_DEFAULT;
+import static org.apache.geode.cache.Region.SEPARATOR;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.NO_REDUNDANT_COPIES_FOR_REGIONS;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.PRIMARY_TRANSFERS_COMPLETED;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.PRIMARY_TRANSFER_TIME;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.REDUNDANCY_NOT_SATISFIED_FOR_REGIONS;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.REDUNDANCY_SATISFIED_FOR_REGIONS;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.FULLY_SATISFIED_REDUNDANCY;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_FOR_REGION_HEADER;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_FOR_REGION_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_HEADER;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.PARTIALLY_SATISFIED_REDUNDANCY;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.PRIMARIES_INFO_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.SATISFIED_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.SUMMARY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.UNDER_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.ZERO_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.ZERO_REDUNDANT_COPIES;
+import static
org.apache.geode.management.internal.cli.commands.RestoreRedundancyCommand.COMMAND_NAME;
+import static
org.apache.geode.management.internal.cli.commands.RestoreRedundancyCommand.EXCLUDE_REGION;
+import static
org.apache.geode.management.internal.cli.commands.RestoreRedundancyCommand.INCLUDE_REGION;
+import static
org.apache.geode.management.internal.cli.commands.RestoreRedundancyCommand.REASSIGN_PRIMARIES;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.IntStream;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.cache.PartitionAttributesImpl;
+import org.apache.geode.internal.cache.PartitionedRegion;
+import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.assertions.CommandResultAssert;
+import org.apache.geode.test.junit.assertions.InfoResultModelAssert;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+
+public class RestoreRedundancyCommandDUnitTest {
+ @Rule
+ public ClusterStartupRule cluster = new ClusterStartupRule();
+
+ @Rule
+ public GfshCommandRule gfsh = new GfshCommandRule();
+
+ private int locatorPort;
+ private MemberVM locator;
+ private List<MemberVM> servers;
+ private static final int SERVERS_TO_START = 3;
+ private static final String HIGH_REDUNDANCY_REGION_NAME = "highRedundancy";
+ private static final int HIGH_REDUNDANCY_COPIES = SERVERS_TO_START - 1;
+ private static final String LOW_REDUNDANCY_REGION_NAME = "lowRedundancy";
+ private static final String PARENT_REGION_NAME = "colocatedParent";
+ private static final String CHILD_REGION_NAME = "colocatedChild";
+ private static final int SINGLE_REDUNDANT_COPY = 1;
+ private static final String ZERO_REDUNDANCY_REGION_NAME = "zeroRedundancy";
+
+ @Before
+ public void setUp() throws Exception {
+ servers = new ArrayList<>();
+ locator = cluster.startLocatorVM(0);
+ locatorPort = locator.getPort();
+ IntStream.range(0, SERVERS_TO_START)
+ .forEach(i -> servers.add(cluster.startServerVM(i + 1, locatorPort)));
+ gfsh.connectAndVerify(locator);
+ }
+
+ @Test
+ public void
restoreRedundancyWithNoArgumentsRestoresRedundancyForAllRegions() {
+ List<String> regionNames = getAllRegionNames();
+ createAndPopulateRegions(regionNames);
+
+ int numberOfServers = servers.size();
+ regionNames.forEach(region -> locator
+ .waitUntilRegionIsReadyOnExactlyThisManyServers(SEPARATOR + region,
numberOfServers));
+
+ String command = new CommandStringBuilder(COMMAND_NAME).getCommandString();
+
+ CommandResultAssert commandResult =
gfsh.executeAndAssertThat(command).statusIsSuccess()
+ .hasNoSection(ZERO_REDUNDANCY_SECTION)
+ .hasNoSection(UNDER_REDUNDANCY_SECTION);
+
+ InfoResultModelAssert summary =
commandResult.hasInfoSection(SUMMARY_SECTION);
+ summary.hasOutput().contains(ZERO_REDUNDANT_COPIES + 0);
+ summary.hasOutput().contains(PARTIALLY_SATISFIED_REDUNDANCY + 0);
+ summary.hasOutput().contains(FULLY_SATISFIED_REDUNDANCY +
regionNames.size());
+
+ InfoResultModelAssert satisfiedSection =
+ commandResult.hasInfoSection(SATISFIED_REDUNDANCY_SECTION);
+ satisfiedSection.hasHeader().isEqualTo(REDUNDANCY_SATISFIED_FOR_REGIONS);
+ satisfiedSection.hasOutput().contains(regionNames);
Review comment:
This code block is duplicated within the test, it can be extracted to a
separate method.
##########
File path:
geode-gfsh/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/RestoreRedundancyCommandDUnitTest.java
##########
@@ -0,0 +1,618 @@
+/*
+ * 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.apache.geode.cache.PartitionAttributesFactory.GLOBAL_MAX_BUCKETS_DEFAULT;
+import static org.apache.geode.cache.Region.SEPARATOR;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.NO_REDUNDANT_COPIES_FOR_REGIONS;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.PRIMARY_TRANSFERS_COMPLETED;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.PRIMARY_TRANSFER_TIME;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.REDUNDANCY_NOT_SATISFIED_FOR_REGIONS;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.REDUNDANCY_SATISFIED_FOR_REGIONS;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.FULLY_SATISFIED_REDUNDANCY;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_FOR_REGION_HEADER;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_FOR_REGION_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_HEADER;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.PARTIALLY_SATISFIED_REDUNDANCY;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.PRIMARIES_INFO_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.SATISFIED_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.SUMMARY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.UNDER_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.ZERO_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.ZERO_REDUNDANT_COPIES;
+import static
org.apache.geode.management.internal.cli.commands.RestoreRedundancyCommand.COMMAND_NAME;
+import static
org.apache.geode.management.internal.cli.commands.RestoreRedundancyCommand.EXCLUDE_REGION;
+import static
org.apache.geode.management.internal.cli.commands.RestoreRedundancyCommand.INCLUDE_REGION;
+import static
org.apache.geode.management.internal.cli.commands.RestoreRedundancyCommand.REASSIGN_PRIMARIES;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.IntStream;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.cache.PartitionAttributesImpl;
+import org.apache.geode.internal.cache.PartitionedRegion;
+import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.assertions.CommandResultAssert;
+import org.apache.geode.test.junit.assertions.InfoResultModelAssert;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+
+public class RestoreRedundancyCommandDUnitTest {
+ @Rule
+ public ClusterStartupRule cluster = new ClusterStartupRule();
+
+ @Rule
+ public GfshCommandRule gfsh = new GfshCommandRule();
+
+ private int locatorPort;
+ private MemberVM locator;
+ private List<MemberVM> servers;
+ private static final int SERVERS_TO_START = 3;
+ private static final String HIGH_REDUNDANCY_REGION_NAME = "highRedundancy";
+ private static final int HIGH_REDUNDANCY_COPIES = SERVERS_TO_START - 1;
+ private static final String LOW_REDUNDANCY_REGION_NAME = "lowRedundancy";
+ private static final String PARENT_REGION_NAME = "colocatedParent";
+ private static final String CHILD_REGION_NAME = "colocatedChild";
+ private static final int SINGLE_REDUNDANT_COPY = 1;
+ private static final String ZERO_REDUNDANCY_REGION_NAME = "zeroRedundancy";
+
+ @Before
+ public void setUp() throws Exception {
+ servers = new ArrayList<>();
+ locator = cluster.startLocatorVM(0);
+ locatorPort = locator.getPort();
+ IntStream.range(0, SERVERS_TO_START)
+ .forEach(i -> servers.add(cluster.startServerVM(i + 1, locatorPort)));
+ gfsh.connectAndVerify(locator);
+ }
+
+ @Test
+ public void
restoreRedundancyWithNoArgumentsRestoresRedundancyForAllRegions() {
+ List<String> regionNames = getAllRegionNames();
+ createAndPopulateRegions(regionNames);
+
+ int numberOfServers = servers.size();
+ regionNames.forEach(region -> locator
+ .waitUntilRegionIsReadyOnExactlyThisManyServers(SEPARATOR + region,
numberOfServers));
+
+ String command = new CommandStringBuilder(COMMAND_NAME).getCommandString();
+
+ CommandResultAssert commandResult =
gfsh.executeAndAssertThat(command).statusIsSuccess()
+ .hasNoSection(ZERO_REDUNDANCY_SECTION)
+ .hasNoSection(UNDER_REDUNDANCY_SECTION);
+
+ InfoResultModelAssert summary =
commandResult.hasInfoSection(SUMMARY_SECTION);
+ summary.hasOutput().contains(ZERO_REDUNDANT_COPIES + 0);
+ summary.hasOutput().contains(PARTIALLY_SATISFIED_REDUNDANCY + 0);
+ summary.hasOutput().contains(FULLY_SATISFIED_REDUNDANCY +
regionNames.size());
+
+ InfoResultModelAssert satisfiedSection =
+ commandResult.hasInfoSection(SATISFIED_REDUNDANCY_SECTION);
+ satisfiedSection.hasHeader().isEqualTo(REDUNDANCY_SATISFIED_FOR_REGIONS);
+ satisfiedSection.hasOutput().contains(regionNames);
+
+ InfoResultModelAssert primariesSection =
commandResult.hasInfoSection(PRIMARIES_INFO_SECTION);
+ primariesSection.hasOutput().contains(PRIMARY_TRANSFERS_COMPLETED,
PRIMARY_TRANSFER_TIME);
+
+ // Confirm all regions have their configured redundancy and that primaries
were balanced
+ int numberOfActiveServers = servers.size();
+ servers.get(0).invoke(() -> {
+ for (String regionName : regionNames) {
+ assertRedundancyStatusForRegion(regionName, true);
+ assertPrimariesBalanced(regionName, numberOfActiveServers, true);
+ }
+ });
+ }
+
+ @Test
+ public void
restoreRedundancyWithIncludeRegionArgumentRestoresOnlyThoseRegions() {
+ List<String> regionNames = getAllRegionNames();
+ createAndPopulateRegions(regionNames);
+
+ int numberOfServers = servers.size();
+ regionNames.forEach(region -> locator
+ .waitUntilRegionIsReadyOnExactlyThisManyServers(SEPARATOR + region,
numberOfServers));
+
+ String regionToInclude = HIGH_REDUNDANCY_REGION_NAME;
+ List<String> nonIncludedRegions = new ArrayList<>(regionNames);
+ nonIncludedRegions.remove(regionToInclude);
+
+ String command = new CommandStringBuilder(COMMAND_NAME)
+ .addOption(INCLUDE_REGION, regionToInclude).getCommandString();
+
+ CommandResultAssert commandResult =
gfsh.executeAndAssertThat(command).statusIsSuccess()
+ .hasNoSection(ZERO_REDUNDANCY_SECTION)
+ .hasNoSection(UNDER_REDUNDANCY_SECTION)
+ .doesNotContainOutput(nonIncludedRegions.toArray(new String[0]));
+
+ InfoResultModelAssert summary =
commandResult.hasInfoSection(SUMMARY_SECTION);
+ summary.hasOutput().contains(ZERO_REDUNDANT_COPIES + 0);
+ summary.hasOutput().contains(PARTIALLY_SATISFIED_REDUNDANCY + 0);
+ summary.hasOutput().contains(FULLY_SATISFIED_REDUNDANCY + 1);
+
+ InfoResultModelAssert satisfiedSection =
+ commandResult.hasInfoSection(SATISFIED_REDUNDANCY_SECTION);
+ satisfiedSection.hasHeader().isEqualTo(REDUNDANCY_SATISFIED_FOR_REGIONS);
+ satisfiedSection.hasOutput().contains(regionToInclude);
Review comment:
This code block is duplicated within the test, it can be extracted to a
separate method.
##########
File path:
geode-gfsh/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/RestoreRedundancyCommandDUnitTest.java
##########
@@ -0,0 +1,618 @@
+/*
+ * 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.apache.geode.cache.PartitionAttributesFactory.GLOBAL_MAX_BUCKETS_DEFAULT;
+import static org.apache.geode.cache.Region.SEPARATOR;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.NO_REDUNDANT_COPIES_FOR_REGIONS;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.PRIMARY_TRANSFERS_COMPLETED;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.PRIMARY_TRANSFER_TIME;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.REDUNDANCY_NOT_SATISFIED_FOR_REGIONS;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.REDUNDANCY_SATISFIED_FOR_REGIONS;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.FULLY_SATISFIED_REDUNDANCY;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_FOR_REGION_HEADER;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_FOR_REGION_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_HEADER;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.PARTIALLY_SATISFIED_REDUNDANCY;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.PRIMARIES_INFO_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.SATISFIED_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.SUMMARY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.UNDER_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.ZERO_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.ZERO_REDUNDANT_COPIES;
+import static
org.apache.geode.management.internal.cli.commands.RestoreRedundancyCommand.COMMAND_NAME;
+import static
org.apache.geode.management.internal.cli.commands.RestoreRedundancyCommand.EXCLUDE_REGION;
+import static
org.apache.geode.management.internal.cli.commands.RestoreRedundancyCommand.INCLUDE_REGION;
+import static
org.apache.geode.management.internal.cli.commands.RestoreRedundancyCommand.REASSIGN_PRIMARIES;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.IntStream;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.cache.PartitionAttributesImpl;
+import org.apache.geode.internal.cache.PartitionedRegion;
+import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.assertions.CommandResultAssert;
+import org.apache.geode.test.junit.assertions.InfoResultModelAssert;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+
+public class RestoreRedundancyCommandDUnitTest {
+ @Rule
+ public ClusterStartupRule cluster = new ClusterStartupRule();
+
+ @Rule
+ public GfshCommandRule gfsh = new GfshCommandRule();
+
+ private int locatorPort;
+ private MemberVM locator;
+ private List<MemberVM> servers;
+ private static final int SERVERS_TO_START = 3;
+ private static final String HIGH_REDUNDANCY_REGION_NAME = "highRedundancy";
+ private static final int HIGH_REDUNDANCY_COPIES = SERVERS_TO_START - 1;
+ private static final String LOW_REDUNDANCY_REGION_NAME = "lowRedundancy";
+ private static final String PARENT_REGION_NAME = "colocatedParent";
+ private static final String CHILD_REGION_NAME = "colocatedChild";
+ private static final int SINGLE_REDUNDANT_COPY = 1;
+ private static final String ZERO_REDUNDANCY_REGION_NAME = "zeroRedundancy";
+
+ @Before
+ public void setUp() throws Exception {
+ servers = new ArrayList<>();
+ locator = cluster.startLocatorVM(0);
+ locatorPort = locator.getPort();
+ IntStream.range(0, SERVERS_TO_START)
+ .forEach(i -> servers.add(cluster.startServerVM(i + 1, locatorPort)));
+ gfsh.connectAndVerify(locator);
+ }
+
+ @Test
+ public void
restoreRedundancyWithNoArgumentsRestoresRedundancyForAllRegions() {
+ List<String> regionNames = getAllRegionNames();
+ createAndPopulateRegions(regionNames);
+
+ int numberOfServers = servers.size();
+ regionNames.forEach(region -> locator
+ .waitUntilRegionIsReadyOnExactlyThisManyServers(SEPARATOR + region,
numberOfServers));
+
+ String command = new CommandStringBuilder(COMMAND_NAME).getCommandString();
+
+ CommandResultAssert commandResult =
gfsh.executeAndAssertThat(command).statusIsSuccess()
+ .hasNoSection(ZERO_REDUNDANCY_SECTION)
+ .hasNoSection(UNDER_REDUNDANCY_SECTION);
+
+ InfoResultModelAssert summary =
commandResult.hasInfoSection(SUMMARY_SECTION);
+ summary.hasOutput().contains(ZERO_REDUNDANT_COPIES + 0);
+ summary.hasOutput().contains(PARTIALLY_SATISFIED_REDUNDANCY + 0);
+ summary.hasOutput().contains(FULLY_SATISFIED_REDUNDANCY +
regionNames.size());
+
+ InfoResultModelAssert satisfiedSection =
+ commandResult.hasInfoSection(SATISFIED_REDUNDANCY_SECTION);
+ satisfiedSection.hasHeader().isEqualTo(REDUNDANCY_SATISFIED_FOR_REGIONS);
+ satisfiedSection.hasOutput().contains(regionNames);
+
+ InfoResultModelAssert primariesSection =
commandResult.hasInfoSection(PRIMARIES_INFO_SECTION);
+ primariesSection.hasOutput().contains(PRIMARY_TRANSFERS_COMPLETED,
PRIMARY_TRANSFER_TIME);
+
+ // Confirm all regions have their configured redundancy and that primaries
were balanced
+ int numberOfActiveServers = servers.size();
+ servers.get(0).invoke(() -> {
+ for (String regionName : regionNames) {
+ assertRedundancyStatusForRegion(regionName, true);
+ assertPrimariesBalanced(regionName, numberOfActiveServers, true);
+ }
+ });
+ }
+
+ @Test
+ public void
restoreRedundancyWithIncludeRegionArgumentRestoresOnlyThoseRegions() {
+ List<String> regionNames = getAllRegionNames();
+ createAndPopulateRegions(regionNames);
+
+ int numberOfServers = servers.size();
+ regionNames.forEach(region -> locator
+ .waitUntilRegionIsReadyOnExactlyThisManyServers(SEPARATOR + region,
numberOfServers));
+
+ String regionToInclude = HIGH_REDUNDANCY_REGION_NAME;
+ List<String> nonIncludedRegions = new ArrayList<>(regionNames);
+ nonIncludedRegions.remove(regionToInclude);
+
+ String command = new CommandStringBuilder(COMMAND_NAME)
+ .addOption(INCLUDE_REGION, regionToInclude).getCommandString();
Review comment:
This code block is duplicated within the test, it can be extracted to a
separate method.
##########
File path:
geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/StatusRedundancyCommand.java
##########
@@ -0,0 +1,121 @@
+/*
+ * 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.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.REDUNDANCY_COMMAND_ADDED_VERSION;
+import static
org.apache.geode.management.internal.functions.CliFunctionResult.StatusState.ERROR;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.GfshCommand;
+import
org.apache.geode.management.internal.cli.functions.RedundancyCommandFunction;
+import org.apache.geode.management.internal.cli.result.model.ResultModel;
+import org.apache.geode.management.internal.functions.CliFunctionResult;
+import org.apache.geode.management.internal.i18n.CliStrings;
+import
org.apache.geode.management.internal.operation.RebalanceOperationPerformer;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class StatusRedundancyCommand extends GfshCommand {
+ static final String COMMAND_NAME = "status redundancy";
+ private static final String COMMAND_HELP =
+ "Report the redundancy status for partitioned regions in connected
members. The default is to report status for all regions.";
+ static final String INCLUDE_REGION = "include-region";
Review comment:
Maybe use `regions` instead of `region`?.
##########
File path:
geode-gfsh/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/StatusRedundancyCommandDUnitTest.java
##########
@@ -0,0 +1,281 @@
+/*
+ * 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.apache.geode.cache.PartitionAttributesFactory.GLOBAL_MAX_BUCKETS_DEFAULT;
+import static org.apache.geode.cache.Region.SEPARATOR;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.NO_REDUNDANT_COPIES_FOR_REGIONS;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.REDUNDANCY_NOT_SATISFIED_FOR_REGIONS;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.REDUNDANCY_SATISFIED_FOR_REGIONS;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.FULLY_SATISFIED_REDUNDANCY;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_FOR_REGION_HEADER;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_FOR_REGION_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_HEADER;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.PARTIALLY_SATISFIED_REDUNDANCY;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.SATISFIED_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.SUMMARY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.UNDER_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.ZERO_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.ZERO_REDUNDANT_COPIES;
+import static
org.apache.geode.management.internal.cli.commands.StatusRedundancyCommand.COMMAND_NAME;
+import static
org.apache.geode.management.internal.cli.commands.StatusRedundancyCommand.EXCLUDE_REGION;
+import static
org.apache.geode.management.internal.cli.commands.StatusRedundancyCommand.INCLUDE_REGION;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.IntStream;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.cache.PartitionAttributesImpl;
+import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.assertions.CommandResultAssert;
+import org.apache.geode.test.junit.assertions.InfoResultModelAssert;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+
+public class StatusRedundancyCommandDUnitTest {
+ @Rule
+ public ClusterStartupRule cluster = new ClusterStartupRule();
+
+ @Rule
+ public GfshCommandRule gfsh = new GfshCommandRule();
+
+ private int locatorPort;
+ private MemberVM locator;
+ private List<MemberVM> servers;
+ private static final int SERVERS_TO_START = 2;
+ private static final String SATISFIED_REGION = "satisfiedRedundancy";
+ private static final int SATISFIABLE_COPIES = SERVERS_TO_START - 1;
+ private static final String UNSATISFIED_REGION = "unsatisfiedRedundancy";
+ private static final int UNSATISFIABLE_COPIES = SERVERS_TO_START;
+ private static final String NO_CONFIGURED_REDUNDANCY_REGION =
"noConfiguredRedundancy";
+ private static final String ZERO_COPIES_REGION = "zeroRedundantCopies";
+ private static final List<String> regionNames =
Arrays.asList(SATISFIED_REGION,
+ UNSATISFIED_REGION, NO_CONFIGURED_REDUNDANCY_REGION, ZERO_COPIES_REGION);
+
+ @Before
+ public void setUp() throws Exception {
+ servers = new ArrayList<>();
+ locator = cluster.startLocatorVM(0);
+ locatorPort = locator.getPort();
+ IntStream.range(0, SERVERS_TO_START)
+ .forEach(i -> servers.add(cluster.startServerVM(i + 1, locatorPort)));
+ gfsh.connectAndVerify(locator);
+ }
+
+ @Test
+ public void statusRedundancyWithNoArgumentsReturnsStatusForAllRegions() {
+ createAndPopulateRegions();
+
+ String command = new CommandStringBuilder(COMMAND_NAME).getCommandString();
+
+ CommandResultAssert commandResult = gfsh.executeAndAssertThat(command);
+ commandResult.statusIsSuccess();
+
+ verifySummarySection(commandResult, 1, 1, 2);
+
+ InfoResultModelAssert zeroRedundancy =
commandResult.hasInfoSection(ZERO_REDUNDANCY_SECTION);
+ zeroRedundancy.hasHeader().isEqualTo(NO_REDUNDANT_COPIES_FOR_REGIONS);
+ zeroRedundancy.hasOutput().contains(ZERO_COPIES_REGION);
+
+ InfoResultModelAssert underRedundancy =
commandResult.hasInfoSection(UNDER_REDUNDANCY_SECTION);
+
underRedundancy.hasHeader().isEqualTo(REDUNDANCY_NOT_SATISFIED_FOR_REGIONS);
+ underRedundancy.hasOutput().contains(UNSATISFIED_REGION);
+
+ InfoResultModelAssert satisfiedRedundancy =
+ commandResult.hasInfoSection(SATISFIED_REDUNDANCY_SECTION);
+
satisfiedRedundancy.hasHeader().isEqualTo(REDUNDANCY_SATISFIED_FOR_REGIONS);
+ satisfiedRedundancy.hasOutput().contains(SATISFIED_REGION,
+ NO_CONFIGURED_REDUNDANCY_REGION);
+ }
+
+ @Test
+ public void
statusRedundancyWithIncludeRegionArgumentReturnsStatusForOnlyThatRegion() {
+ createAndPopulateRegions();
+
+ String command = new CommandStringBuilder(COMMAND_NAME)
+ .addOption(INCLUDE_REGION, SATISFIED_REGION)
+ .getCommandString();
+
+ CommandResultAssert commandResult = gfsh.executeAndAssertThat(command);
+ commandResult.statusIsSuccess()
+ .hasNoSection(ZERO_REDUNDANCY_SECTION)
+ .hasNoSection(UNDER_REDUNDANCY_SECTION)
+ .doesNotContainOutput(UNSATISFIED_REGION)
+ .doesNotContainOutput(ZERO_COPIES_REGION)
+ .doesNotContainOutput(NO_CONFIGURED_REDUNDANCY_REGION);
+
+ verifySummarySection(commandResult, 0, 0, 1);
+
+ InfoResultModelAssert satisfiedRedundancy =
+ commandResult.hasInfoSection(SATISFIED_REDUNDANCY_SECTION);
+
satisfiedRedundancy.hasHeader().isEqualTo(REDUNDANCY_SATISFIED_FOR_REGIONS);
+ satisfiedRedundancy.hasOutput().contains(SATISFIED_REGION);
Review comment:
This code block is duplicated within the test, it can be extracted to a
separate method.
##########
File path:
geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/RestoreRedundancyCommandTest.java
##########
@@ -0,0 +1,256 @@
+/*
+ * 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.apache.geode.management.cli.Result.Status.ERROR;
+import static org.apache.geode.management.cli.Result.Status.OK;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.REDUNDANCY_COMMAND_ADDED_VERSION;
+import static org.hamcrest.CoreMatchers.everyItem;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.internal.functions.CliFunctionResult;
+import
org.apache.geode.management.internal.operation.RebalanceOperationPerformer;
+
+public class RestoreRedundancyCommandTest {
+
+ private RestoreRedundancyCommand command;
+ private final String includeRegion1 = "include1";
+ private final String includeRegion2 = "include2";
+ private String[] includeRegions = {includeRegion1, includeRegion2};
+ private final String excludeRegion1 = "exclude1";
+ private final String excludeRegion2 = "exclude2";
+ private String[] excludeRegions = {excludeRegion1, excludeRegion2};
+ private final boolean shouldReassignPrimaries = true;
+ private DistributedMember mockMember1;
+ private DistributedMember mockMember2;
+ private CliFunctionResult successFunctionResult;
+ private CliFunctionResult errorFunctionResult;
+ private RedundancyCommandUtils mockUtils;
+ private Object[] expectedArguments;
+
+ @Before
+ public void setUp() {
+ mockMember1 = mock(DistributedMember.class);
+ mockMember2 = mock(DistributedMember.class);
+ expectedArguments = new Object[] {includeRegions, excludeRegions,
shouldReassignPrimaries};
+
+ successFunctionResult = mock(CliFunctionResult.class);
+ when(successFunctionResult.getStatus()).thenReturn(OK.name());
+
+ errorFunctionResult = mock(CliFunctionResult.class);
+ when(errorFunctionResult.getStatus()).thenReturn(ERROR.name());
+
+ mockUtils = mock(RedundancyCommandUtils.class);
+ Cache mockCache = mock(InternalCache.class);
+
+ command = spy(new RestoreRedundancyCommand());
+ doReturn(mockUtils).when(command).getUtils();
+ doReturn(mockCache).when(command).getCache();
+ }
+
+ @Test
+ public void
executeCallsGetNoViableMembersResultWhenNoViableMembersAreFoundForAtLeastOneRegion()
{
+ RebalanceOperationPerformer.MemberPRInfo firstMemberPRInfo =
+ new RebalanceOperationPerformer.MemberPRInfo();
+ String region1 = "region1";
+ firstMemberPRInfo.region = region1;
+ RebalanceOperationPerformer.MemberPRInfo secondMemberPRInfo =
+ new RebalanceOperationPerformer.MemberPRInfo();
+ String region2 = "region2";
+ secondMemberPRInfo.region = region2;
+
+ // Put something in the members list when we call populateLists
+ doAnswer(invocation -> {
+ List<RebalanceOperationPerformer.MemberPRInfo> memberPRInfoList =
invocation.getArgument(0);
+ memberPRInfoList.add(firstMemberPRInfo);
+ memberPRInfoList.add(secondMemberPRInfo);
+ return null;
+ }).when(mockUtils).populateLists(any(), any(), any(), any(), any());
+
+ List<DistributedMember> viableMembers = new ArrayList<>();
+ viableMembers.add(mock(DistributedMember.class));
+
+ when(mockUtils.filterViableMembersForVersion(eq(firstMemberPRInfo), any()))
+ .thenReturn(viableMembers);
+ when(mockUtils.filterViableMembersForVersion(eq(secondMemberPRInfo),
any()))
+ .thenReturn(Collections.emptyList());
+
+ command.execute(includeRegions, excludeRegions, shouldReassignPrimaries);
+
+ verify(mockUtils, times(1)).getNoViableMembersResult(any(), eq(region2));
+ verify(mockUtils, times(0)).getNoViableMembersResult(any(), eq(region1));
+ }
+
+ @Test
+ public void
executeCallsMethodsWithCorrectArgumentsWhenViableMembersAreFoundForAllRegions()
{
+ RebalanceOperationPerformer.MemberPRInfo firstMemberPRInfo =
+ mock(RebalanceOperationPerformer.MemberPRInfo.class);
+ RebalanceOperationPerformer.MemberPRInfo secondMemberPRInfo =
+ mock(RebalanceOperationPerformer.MemberPRInfo.class);
+ List<RebalanceOperationPerformer.MemberPRInfo> membersForEachRegion = new
ArrayList<>();
+ membersForEachRegion.add(firstMemberPRInfo);
+ membersForEachRegion.add(secondMemberPRInfo);
+
+ // Put something in the members list when we call populateLists
+ doAnswer(invocation -> {
+ List<RebalanceOperationPerformer.MemberPRInfo> memberPRInfoList =
invocation.getArgument(0);
+ memberPRInfoList.add(firstMemberPRInfo);
+ memberPRInfoList.add(secondMemberPRInfo);
+ return null;
+ }).when(mockUtils).populateLists(any(), any(), any(), any(), any());
+
+ // Allow us to get past the filter viable members step
+ List<DistributedMember> viableMembers = new ArrayList<>();
+ viableMembers.add(mock(DistributedMember.class));
+ when(mockUtils.filterViableMembersForVersion(any(),
any())).thenReturn(viableMembers);
+
+ // Prevent the executeFunctionOnMembers method from doing anything
+ List<CliFunctionResult> returnedList = new ArrayList<>();
+ doReturn(returnedList).when(command).executeFunctionOnMembers(any(),
any(), anyBoolean(),
+ any());
+
+ command.execute(includeRegions, excludeRegions, shouldReassignPrimaries);
+
+ // Confirm we set the correct viable members on the memberPRInfos
+ verify(mockUtils,
times(1)).filterViableMembersForVersion(firstMemberPRInfo,
+ REDUNDANCY_COMMAND_ADDED_VERSION);
+ verify(mockUtils,
times(1)).filterViableMembersForVersion(secondMemberPRInfo,
+ REDUNDANCY_COMMAND_ADDED_VERSION);
+ assertThat(firstMemberPRInfo.dsMemberList, is(viableMembers));
+ assertThat(secondMemberPRInfo.dsMemberList, is(viableMembers));
+
+ // Confirm we called executeFunctionOnMembers and
buildResultModelFromFunctionResults with the
+ // correct arguments
+ verify(command, times(1)).executeFunctionOnMembers(includeRegions,
excludeRegions,
+ shouldReassignPrimaries, membersForEachRegion);
+ boolean isStatusCommand = false;
Review comment:
No need for this variable.
##########
File path:
geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/RedundancyCommandUtils.java
##########
@@ -0,0 +1,269 @@
+/*
+ * 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.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.NO_REDUNDANT_COPIES_FOR_REGIONS;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.PRIMARY_TRANSFERS_COMPLETED;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.PRIMARY_TRANSFER_TIME;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.REDUNDANCY_NOT_SATISFIED_FOR_REGIONS;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.REDUNDANCY_SATISFIED_FOR_REGIONS;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.apache.geode.cache.control.RegionRedundancyStatus;
+import org.apache.geode.cache.control.RestoreRedundancyResults;
+import org.apache.geode.distributed.DistributedMember;
+import
org.apache.geode.distributed.internal.membership.InternalDistributedMember;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl;
+import org.apache.geode.internal.serialization.Version;
+import org.apache.geode.management.ManagementService;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.result.model.InfoResultModel;
+import org.apache.geode.management.internal.cli.result.model.ResultModel;
+import org.apache.geode.management.internal.functions.CliFunctionResult;
+import
org.apache.geode.management.internal.operation.RebalanceOperationPerformer;
+
+public class RedundancyCommandUtils {
+ public static final String NO_MEMBERS_WITH_VERSION_FOR_REGION =
+ "No members with a version greater than or equal to %s were found for
region %s";
+ public static final String NO_MEMBERS_SECTION = "no-members";
+ public static final String NO_MEMBERS_HEADER =
+ "No partitioned regions were found.";
+ public static final String NO_MEMBERS_FOR_REGION_SECTION =
"no-members-for-region";
+ public static final String NO_MEMBERS_FOR_REGION_HEADER =
+ "No members hosting the following regions were found: ";
+ public static final String ERROR_SECTION = "errors";
+ public static final String ERROR_SECTION_HEADER =
+ "The following errors or exceptions were encountered: ";
+ public static final String SUMMARY_SECTION = "summary-section";
+ public static final String ZERO_REDUNDANT_COPIES =
+ "Number of regions with zero redundant copies = ";
+ public static final String PARTIALLY_SATISFIED_REDUNDANCY =
+ "Number of regions with partially satisfied redundancy = ";
+ public static final String FULLY_SATISFIED_REDUNDANCY =
+ "Number of regions with fully satisfied redundancy = ";
+ public static final String ZERO_REDUNDANCY_SECTION = "zero-redundancy";
+ public static final String UNDER_REDUNDANCY_SECTION = "under-redundancy";
+ public static final String SATISFIED_REDUNDANCY_SECTION =
"satisfied-redundancy";
+ public static final String PRIMARIES_INFO_SECTION = "primaries-info";
+ public static final String EXCEPTION_MEMBER_MESSAGE = "Exception occurred on
member %s: %s";
+ public static final Version REDUNDANCY_COMMAND_ADDED_VERSION =
Version.GEODE_1_13_0;
+ public static final String INDENT = " ";
+
+ void populateLists(List<RebalanceOperationPerformer.MemberPRInfo>
membersForEachRegion,
+ List<String> noMemberRegions, String[] includeRegions, String[]
excludeRegions,
+ InternalCache cache) {
+ // Include all regions
+ if (includeRegions == null) {
+ // Exclude these regions
+ List<String> excludedRegionList =
+ excludeRegions != null ? Arrays.asList(excludeRegions) : new
ArrayList<>();
+
+ List<RebalanceOperationPerformer.MemberPRInfo> memberRegionList =
+ getMembersForEachRegion(excludedRegionList, cache);
+ membersForEachRegion.addAll(memberRegionList);
+ } else {
+ for (String regionName : includeRegions) {
+ DistributedMember memberForRegion = getOneMemberForRegion(regionName,
cache);
+
+ // If we did not find a member for this region name, add it to the
list of regions with no
+ // members
+ if (memberForRegion == null) {
+ noMemberRegions.add(regionName);
+ } else {
+ RebalanceOperationPerformer.MemberPRInfo memberPRInfo =
+ new RebalanceOperationPerformer.MemberPRInfo();
+ memberPRInfo.region = regionName;
+ memberPRInfo.dsMemberList.add(memberForRegion);
+ membersForEachRegion.add(memberPRInfo);
+ }
+ }
+ }
+ }
+
+ // Extracted for testing
+ List<RebalanceOperationPerformer.MemberPRInfo> getMembersForEachRegion(
+ List<String> excludedRegionList, InternalCache cache) {
+ return RebalanceOperationPerformer.getMemberRegionList(
+ ManagementService.getManagementService(cache), cache,
excludedRegionList);
+ }
+
+ // Extracted for testing
+ DistributedMember getOneMemberForRegion(String regionName, InternalCache
cache) {
+ String regionNameWithSeparator = regionName;
+ // The getAssociatedMembers method requires region names start with '/'
+ if (!regionName.startsWith("/")) {
+ regionNameWithSeparator = "/" + regionName;
Review comment:
Maybe use `CacheConfig.SEPARATOR` instead of hardcoding the character?
(I know we don't it consistently across the code, but...).
##########
File path:
geode-gfsh/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/StatusRedundancyCommandDUnitTest.java
##########
@@ -0,0 +1,281 @@
+/*
+ * 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.apache.geode.cache.PartitionAttributesFactory.GLOBAL_MAX_BUCKETS_DEFAULT;
+import static org.apache.geode.cache.Region.SEPARATOR;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.NO_REDUNDANT_COPIES_FOR_REGIONS;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.REDUNDANCY_NOT_SATISFIED_FOR_REGIONS;
+import static
org.apache.geode.internal.cache.control.RestoreRedundancyResultsImpl.REDUNDANCY_SATISFIED_FOR_REGIONS;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.FULLY_SATISFIED_REDUNDANCY;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_FOR_REGION_HEADER;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_FOR_REGION_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_HEADER;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.NO_MEMBERS_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.PARTIALLY_SATISFIED_REDUNDANCY;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.SATISFIED_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.SUMMARY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.UNDER_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.ZERO_REDUNDANCY_SECTION;
+import static
org.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.ZERO_REDUNDANT_COPIES;
+import static
org.apache.geode.management.internal.cli.commands.StatusRedundancyCommand.COMMAND_NAME;
+import static
org.apache.geode.management.internal.cli.commands.StatusRedundancyCommand.EXCLUDE_REGION;
+import static
org.apache.geode.management.internal.cli.commands.StatusRedundancyCommand.INCLUDE_REGION;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.IntStream;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.cache.PartitionAttributesImpl;
+import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.assertions.CommandResultAssert;
+import org.apache.geode.test.junit.assertions.InfoResultModelAssert;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+
+public class StatusRedundancyCommandDUnitTest {
+ @Rule
+ public ClusterStartupRule cluster = new ClusterStartupRule();
+
+ @Rule
+ public GfshCommandRule gfsh = new GfshCommandRule();
+
+ private int locatorPort;
+ private MemberVM locator;
+ private List<MemberVM> servers;
+ private static final int SERVERS_TO_START = 2;
+ private static final String SATISFIED_REGION = "satisfiedRedundancy";
+ private static final int SATISFIABLE_COPIES = SERVERS_TO_START - 1;
+ private static final String UNSATISFIED_REGION = "unsatisfiedRedundancy";
+ private static final int UNSATISFIABLE_COPIES = SERVERS_TO_START;
+ private static final String NO_CONFIGURED_REDUNDANCY_REGION =
"noConfiguredRedundancy";
+ private static final String ZERO_COPIES_REGION = "zeroRedundantCopies";
+ private static final List<String> regionNames =
Arrays.asList(SATISFIED_REGION,
+ UNSATISFIED_REGION, NO_CONFIGURED_REDUNDANCY_REGION, ZERO_COPIES_REGION);
+
+ @Before
+ public void setUp() throws Exception {
+ servers = new ArrayList<>();
+ locator = cluster.startLocatorVM(0);
+ locatorPort = locator.getPort();
+ IntStream.range(0, SERVERS_TO_START)
+ .forEach(i -> servers.add(cluster.startServerVM(i + 1, locatorPort)));
+ gfsh.connectAndVerify(locator);
+ }
+
+ @Test
+ public void statusRedundancyWithNoArgumentsReturnsStatusForAllRegions() {
+ createAndPopulateRegions();
+
+ String command = new CommandStringBuilder(COMMAND_NAME).getCommandString();
+
+ CommandResultAssert commandResult = gfsh.executeAndAssertThat(command);
+ commandResult.statusIsSuccess();
+
+ verifySummarySection(commandResult, 1, 1, 2);
+
+ InfoResultModelAssert zeroRedundancy =
commandResult.hasInfoSection(ZERO_REDUNDANCY_SECTION);
+ zeroRedundancy.hasHeader().isEqualTo(NO_REDUNDANT_COPIES_FOR_REGIONS);
+ zeroRedundancy.hasOutput().contains(ZERO_COPIES_REGION);
+
+ InfoResultModelAssert underRedundancy =
commandResult.hasInfoSection(UNDER_REDUNDANCY_SECTION);
+
underRedundancy.hasHeader().isEqualTo(REDUNDANCY_NOT_SATISFIED_FOR_REGIONS);
+ underRedundancy.hasOutput().contains(UNSATISFIED_REGION);
+
+ InfoResultModelAssert satisfiedRedundancy =
+ commandResult.hasInfoSection(SATISFIED_REDUNDANCY_SECTION);
+
satisfiedRedundancy.hasHeader().isEqualTo(REDUNDANCY_SATISFIED_FOR_REGIONS);
+ satisfiedRedundancy.hasOutput().contains(SATISFIED_REGION,
+ NO_CONFIGURED_REDUNDANCY_REGION);
+ }
+
+ @Test
+ public void
statusRedundancyWithIncludeRegionArgumentReturnsStatusForOnlyThatRegion() {
+ createAndPopulateRegions();
+
+ String command = new CommandStringBuilder(COMMAND_NAME)
+ .addOption(INCLUDE_REGION, SATISFIED_REGION)
+ .getCommandString();
+
+ CommandResultAssert commandResult = gfsh.executeAndAssertThat(command);
+ commandResult.statusIsSuccess()
+ .hasNoSection(ZERO_REDUNDANCY_SECTION)
+ .hasNoSection(UNDER_REDUNDANCY_SECTION)
+ .doesNotContainOutput(UNSATISFIED_REGION)
+ .doesNotContainOutput(ZERO_COPIES_REGION)
+ .doesNotContainOutput(NO_CONFIGURED_REDUNDANCY_REGION);
+
+ verifySummarySection(commandResult, 0, 0, 1);
+
+ InfoResultModelAssert satisfiedRedundancy =
+ commandResult.hasInfoSection(SATISFIED_REDUNDANCY_SECTION);
+
satisfiedRedundancy.hasHeader().isEqualTo(REDUNDANCY_SATISFIED_FOR_REGIONS);
+ satisfiedRedundancy.hasOutput().contains(SATISFIED_REGION);
+ }
+
+ @Test
+ public void
statusRedundancyWithExcludeRegionArgumentReturnsStatusForAllExceptThatRegion() {
+ createAndPopulateRegions();
+
+ String command = new CommandStringBuilder(COMMAND_NAME)
+ .addOption(EXCLUDE_REGION, ZERO_COPIES_REGION)
+ .getCommandString();
+
+ CommandResultAssert commandResult = gfsh.executeAndAssertThat(command);
+ commandResult.statusIsSuccess()
+ .hasNoSection(ZERO_REDUNDANCY_SECTION)
+ .doesNotContainOutput(ZERO_COPIES_REGION);
+
+ verifySummarySection(commandResult, 0, 1, 2);
+
+ InfoResultModelAssert underRedundancy =
commandResult.hasInfoSection(UNDER_REDUNDANCY_SECTION);
+
underRedundancy.hasHeader().isEqualTo(REDUNDANCY_NOT_SATISFIED_FOR_REGIONS);
+ underRedundancy.hasOutput().contains(UNSATISFIED_REGION);
+
+ InfoResultModelAssert satisfiedRedundancy =
+ commandResult.hasInfoSection(SATISFIED_REDUNDANCY_SECTION);
+
satisfiedRedundancy.hasHeader().isEqualTo(REDUNDANCY_SATISFIED_FOR_REGIONS);
+ satisfiedRedundancy.hasOutput().contains(SATISFIED_REGION,
+ NO_CONFIGURED_REDUNDANCY_REGION);
Review comment:
This code block is duplicated within the test, it can be extracted to a
separate method.
##########
File path:
geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/StatusRedundancyCommand.java
##########
@@ -0,0 +1,121 @@
+/*
+ * 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.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.REDUNDANCY_COMMAND_ADDED_VERSION;
+import static
org.apache.geode.management.internal.functions.CliFunctionResult.StatusState.ERROR;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.GfshCommand;
+import
org.apache.geode.management.internal.cli.functions.RedundancyCommandFunction;
+import org.apache.geode.management.internal.cli.result.model.ResultModel;
+import org.apache.geode.management.internal.functions.CliFunctionResult;
+import org.apache.geode.management.internal.i18n.CliStrings;
+import
org.apache.geode.management.internal.operation.RebalanceOperationPerformer;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class StatusRedundancyCommand extends GfshCommand {
+ static final String COMMAND_NAME = "status redundancy";
+ private static final String COMMAND_HELP =
+ "Report the redundancy status for partitioned regions in connected
members. The default is to report status for all regions.";
+ static final String INCLUDE_REGION = "include-region";
+ private static final String INCLUDE_REGION_HELP =
+ "Partitioned regions to be included when reporting redundancy status.
Includes take precedence over excludes.";
+ static final String EXCLUDE_REGION = "exclude-region";
+ private static final String EXCLUDE_REGION_HELP =
+ "Partitioned regions to be excluded when reporting redundancy status.";
+
+ @CliCommand(value = COMMAND_NAME, help = COMMAND_HELP)
+ @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_DATA,
CliStrings.TOPIC_GEODE_REGION})
+ @ResourceOperation(resource = ResourcePermission.Resource.DATA,
+ operation = ResourcePermission.Operation.READ)
+ public ResultModel execute(
+ @CliOption(key = INCLUDE_REGION, help = INCLUDE_REGION_HELP) String[]
includeRegions,
+ @CliOption(key = EXCLUDE_REGION, help = EXCLUDE_REGION_HELP) String[]
excludeRegions) {
+ RedundancyCommandUtils utils = getUtils();
+
+ List<RebalanceOperationPerformer.MemberPRInfo> membersForEachRegion = new
ArrayList<>();
+ List<String> includedRegionsWithNoMembers = new ArrayList<>();
+
+ utils.populateLists(membersForEachRegion, includedRegionsWithNoMembers,
includeRegions,
+ excludeRegions, (InternalCache) getCache());
+
+ for (RebalanceOperationPerformer.MemberPRInfo prInfo :
membersForEachRegion) {
+ // Filter out any members using older versions of Geode
+ List<DistributedMember> viableMembers =
+ utils.filterViableMembersForVersion(prInfo,
REDUNDANCY_COMMAND_ADDED_VERSION);
+
+ if (viableMembers.size() == 0) {
+ // If no viable members were found, return with error status
+ return
utils.getNoViableMembersResult(REDUNDANCY_COMMAND_ADDED_VERSION, prInfo.region);
+ } else {
+ // Update the MemberPRInfo with the viable members
+ prInfo.dsMemberList = viableMembers;
+ }
+ }
+
+ List<CliFunctionResult> functionResults =
+ executeFunctionOnMembers(includeRegions, excludeRegions,
membersForEachRegion);
+
+ return utils.buildResultModelFromFunctionResults(functionResults,
includedRegionsWithNoMembers,
+ true);
+ }
+
+ List<CliFunctionResult> executeFunctionOnMembers(String[] includeRegions,
String[] excludeRegions,
+ List<RebalanceOperationPerformer.MemberPRInfo> membersForEachRegion) {
+
+ List<CliFunctionResult> functionResults = new ArrayList<>();
+ boolean shouldNotReassignPrimaries = false;
Review comment:
Unneeded variable.
##########
File path:
geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/StatusRedundancyCommand.java
##########
@@ -0,0 +1,121 @@
+/*
+ * 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.apache.geode.management.internal.cli.commands.RedundancyCommandUtils.REDUNDANCY_COMMAND_ADDED_VERSION;
+import static
org.apache.geode.management.internal.functions.CliFunctionResult.StatusState.ERROR;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.GfshCommand;
+import
org.apache.geode.management.internal.cli.functions.RedundancyCommandFunction;
+import org.apache.geode.management.internal.cli.result.model.ResultModel;
+import org.apache.geode.management.internal.functions.CliFunctionResult;
+import org.apache.geode.management.internal.i18n.CliStrings;
+import
org.apache.geode.management.internal.operation.RebalanceOperationPerformer;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class StatusRedundancyCommand extends GfshCommand {
+ static final String COMMAND_NAME = "status redundancy";
+ private static final String COMMAND_HELP =
+ "Report the redundancy status for partitioned regions in connected
members. The default is to report status for all regions.";
+ static final String INCLUDE_REGION = "include-region";
+ private static final String INCLUDE_REGION_HELP =
+ "Partitioned regions to be included when reporting redundancy status.
Includes take precedence over excludes.";
+ static final String EXCLUDE_REGION = "exclude-region";
Review comment:
Maybe use `regions` instead of `region`?.
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
> Create restore redundancy and status redundancy gfsh commands
> -------------------------------------------------------------
>
> Key: GEODE-7954
> URL: https://issues.apache.org/jira/browse/GEODE-7954
> Project: Geode
> Issue Type: New Feature
> Components: gfsh
> Reporter: Donal Evans
> Assignee: Donal Evans
> Priority: Major
>
> Add two gfsh commands to allow redundancy to be restored and to check the
> current redundancy status:
> {{restore redundancy [--include-region=value(,value)*]
> [--exclude-region=value(,value)*] [--reassign-primaries(=value)]}}
> {{status redundancy [--include-region=value(,value)*]
> [--exclude-region=value(,value)*]}}
> The first command will execute a function on members hosting the specified
> partitioned regions and trigger the restore redundancy operation for those
> regions, then report the final redundancy status of those regions.
> The command will return success status if:
> * Redundancy is fully satisfied for all regions that were included, either
> explicitly or implicitly.
> * No partitioned regions were found and none were explicitly included.
> The command will return error status if:
> * At least one bucket in a region has zero redundant copies, and that region
> has redundancy configured.
> At least one bucket in a region has fewer than the configured number of
> redundant copies.
> * At least one of the explicitly included partitioned regions is not found.
> * There is a member in the system with a version of Geode older than 1.13.0
> (assuming that is the version in which this feature is implemented).
> * The restore redundancy function encounters an exception.
> The second command will determine the current redundancy status for the
> specified regions and report it to the user.
> Both commands will take optional {{\-\-include-region}} and
> {{\-\-exclude-region}} arguments, similar to the existing rebalance command.
> If neither argument is specified, all regions will be included. Included
> regions will take precedence over excluded regions when both are specified.
> The restore redundancy command will also take an optional
> {{\-\-reassign-primaries}} argument to determine if primaries should be
> reassigned or not during the operation. The default behaviour will be to
> reassign primaries.
> Both commands will output a list of regions with zero redundant copies first
> (unless they are configured to have zero redundancy), then regions with less
> than their configured redundancy, then regions with full redundancy. The
> restore redundancy command will also output information about how many
> primaries were reassigned and how long that process took, similar to the
> existing rebalance command.
> As described here:
> [https://cwiki.apache.org/confluence/display/GEODE/Redundancy+Gfsh+Commands]
--
This message was sent by Atlassian Jira
(v8.3.4#803005)