This is an automated email from the ASF dual-hosted git repository. eshu11 pushed a commit to branch feature/GEODE-8112 in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/feature/GEODE-8112 by this push: new a751251 GEODE-8112: Add --member option in query command. a751251 is described below commit a75125115eaef071d0b537b40c69425aaca5e653 Author: Eric Shu <e...@pivotal.io> AuthorDate: Tue May 12 14:29:50 2020 -0700 GEODE-8112: Add --member option in query command. --- .../geode/management/internal/i18n/CliStrings.java | 2 + .../cli/commands/QueryCommandDUnitTestBase.java | 49 +++++++++++++++ .../commands/QueryCommandIntegrationTestBase.java | 2 +- .../internal/cli/commands/QueryCommand.java | 29 +++++++-- .../internal/cli/commands/QueryCommandTest.java | 72 ++++++++++++++++++++++ 5 files changed, 147 insertions(+), 7 deletions(-) diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/i18n/CliStrings.java b/geode-core/src/main/java/org/apache/geode/management/internal/i18n/CliStrings.java index bb669dd..f660664 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/i18n/CliStrings.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/i18n/CliStrings.java @@ -1823,6 +1823,8 @@ public class CliStrings { "Cannot find regions <{0}> in any of the members"; public static final String QUERY__MSG__NOT_SUPPORTED_ON_MEMBERS = CliStrings.QUERY + " command should be used only from shell. Use QueryService API for running query inside Geode VMs"; + public static final String QUERY__MEMBER__HELP = + "Name/Id of a member which hosts the regions to be queried."; /* 'rebalance' command */ public static final String REBALANCE = "rebalance"; diff --git a/geode-dunit/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommandDUnitTestBase.java b/geode-dunit/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommandDUnitTestBase.java index 919849f..b86e440 100644 --- a/geode-dunit/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommandDUnitTestBase.java +++ b/geode-dunit/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommandDUnitTestBase.java @@ -65,6 +65,10 @@ public class QueryCommandDUnitTestBase { SEPARATOR + DATA_REGION_WITH_EVICTION_NAME; private static final String DATA_PAR_REGION_NAME = "GemfireDataCommandsTestParRegion"; private static final String DATA_PAR_REGION_NAME_PATH = SEPARATOR + DATA_PAR_REGION_NAME; + private static final String DATA_REGION_WITH_PROXY_NAME = + "GemfireDataCommandsTestRegionWithProxy"; + private static final String DATA_REGION_WITH_PROXY_NAME_PATH = + SEPARATOR + DATA_REGION_WITH_PROXY_NAME; private static final String SERIALIZATION_FILTER = "org.apache.geode.management.internal.cli.dto.**"; @@ -256,6 +260,15 @@ public class QueryCommandDUnitTestBase { assertThat(dataRegion.getFullPath()).contains(regionName); } + private static void setupReplicatedProxyRegion(String regionName) { + InternalCache cache = ClusterStartupRule.getCache(); + RegionFactory regionFactory = cache.createRegionFactory(RegionShortcut.REPLICATE_PROXY); + + Region proxyRegion = regionFactory.create(regionName); + assertThat(proxyRegion).isNotNull(); + assertThat(proxyRegion.getFullPath()).contains(regionName); + } + private void validateSelectResult(CommandResult cmdResult, Boolean expectSuccess, Integer expectedRows, String[] cols) { ResultModel rd = cmdResult.getResultData(); @@ -310,4 +323,40 @@ public class QueryCommandDUnitTestBase { this.value1 = value1; } } + + @Test + public void testSimpleQueryWithProxyRegion() { + server1.invoke(() -> setupReplicatedProxyRegion(DATA_REGION_WITH_PROXY_NAME)); + server2.invoke(() -> setupReplicatedRegion(DATA_REGION_WITH_PROXY_NAME)); + locator.waitUntilRegionIsReadyOnExactlyThisManyServers(DATA_REGION_WITH_PROXY_NAME_PATH, 2); + + server1.invoke(() -> prepareDataForRegion(DATA_REGION_WITH_PROXY_NAME_PATH)); + + String member = getHostingMember(); + Random random = new Random(System.nanoTime()); + int randomInteger = random.nextInt(COUNT); + String query = "query --member=" + member + + " --query=\"select ID , status , createTime , pk, floatMinValue from " + + DATA_REGION_WITH_PROXY_NAME_PATH + " where ID <= " + randomInteger + + "\" --interactive=false"; + + CommandResult commandResult = gfsh.executeCommand(query); + validateSelectResult(commandResult, true, (randomInteger + 1), + new String[] {"ID", "status", "createTime", "pk", "floatMinValue"}); + } + + private String getHostingMember() { + String hostingMember = null; + String findMemberCommand = "describe region --name=" + DATA_REGION_WITH_PROXY_NAME; + CommandResult findMemberResult = gfsh.executeCommand(findMemberCommand); + while (findMemberResult.hasNextLine()) { + String s = findMemberResult.nextLine(); + if (s.contains("Hosting Members :")) { + hostingMember = s.substring(s.lastIndexOf(":") + 1); + break; + } + } + assertThat(hostingMember).isNotNull(); + return hostingMember.replaceAll("\\s", ""); + } } diff --git a/geode-dunit/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommandIntegrationTestBase.java b/geode-dunit/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommandIntegrationTestBase.java index 8036787..738a013 100644 --- a/geode-dunit/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommandIntegrationTestBase.java +++ b/geode-dunit/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommandIntegrationTestBase.java @@ -223,7 +223,7 @@ public class QueryCommandIntegrationTestBase { @Test public void queryGivesDescriptiveErrorMessageIfNoQueryIsSpecified() { gfsh.executeAndAssertThat("query").containsOutput( - "You should specify option (--query, --file, --interactive) for this command"); + "You should specify option (--query, --file, --interactive, --member) for this command"); } @Test diff --git a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommand.java b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommand.java index 773adc98..482c75d 100644 --- a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommand.java +++ b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommand.java @@ -60,12 +60,17 @@ public class QueryCommand extends GfshCommand { @CliOption(key = "file", help = "File in which to output the results.", optionContext = ConverterHint.FILE) final File outputFile, @CliOption(key = CliStrings.QUERY__INTERACTIVE, unspecifiedDefaultValue = "false", - help = CliStrings.QUERY__INTERACTIVE__HELP) final boolean interactive) { - DataCommandResult dataResult = select(query); + help = CliStrings.QUERY__INTERACTIVE__HELP) final boolean interactive, + @CliOption(key = CliStrings.MEMBER, + optionContext = ConverterHint.MEMBERIDNAME, + help = CliStrings.QUERY__MEMBER__HELP) final String memberNameOrId) { + + DistributedMember targetMember = memberNameOrId == null ? null : getMember(memberNameOrId); + DataCommandResult dataResult = select(query, targetMember); return dataResult.toSelectCommandResult(); } - private DataCommandResult select(String query) { + DataCommandResult select(String query, DistributedMember targetMember) { Cache cache = getCache(); DataCommandResult dataResult; @@ -97,9 +102,8 @@ public class QueryCommand extends GfshCommand { regionsInQuery = Collections.unmodifiableSet(regions); if (regionsInQuery.size() > 0) { - Set<DistributedMember> members = - ManagementUtils - .getQueryRegionsAssociatedMembers(regionsInQuery, (InternalCache) cache, false); + Set<DistributedMember> members = getMembers(targetMember, (InternalCache) cache, + regionsInQuery); if (members != null && members.size() > 0) { DataCommandFunction function = new DataCommandFunction(); DataCommandRequest request = new DataCommandRequest(); @@ -132,6 +136,19 @@ public class QueryCommand extends GfshCommand { } } + Set<DistributedMember> getMembers(DistributedMember targetMember, InternalCache cache, + Set<String> regionsInQuery) { + return targetMember == null + ? getQueryRegionsAssociatedMembers(cache, regionsInQuery) + : Collections.singleton(targetMember); + } + + Set<DistributedMember> getQueryRegionsAssociatedMembers(InternalCache cache, + Set<String> regionsInQuery) { + return ManagementUtils + .getQueryRegionsAssociatedMembers(regionsInQuery, cache, false); + } + public static DataCommandResult callFunctionForRegion(DataCommandRequest request, DataCommandFunction putfn, Set<DistributedMember> members) { diff --git a/geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/QueryCommandTest.java b/geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/QueryCommandTest.java new file mode 100644 index 0000000..a64bdfc --- /dev/null +++ b/geode-gfsh/src/test/java/org/apache/geode/management/internal/cli/commands/QueryCommandTest.java @@ -0,0 +1,72 @@ +/* + * 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.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.Test; + +import org.apache.geode.distributed.DistributedMember; +import org.apache.geode.internal.cache.InternalCache; +import org.apache.geode.management.internal.cli.domain.DataCommandResult; + +public class QueryCommandTest { + private final QueryCommand command = new QueryCommand(); + + @Test + public void targetMemberIsNotSetIfMemberOptionsIsNotUsed() { + QueryCommand spyCommand = spy(command); + String query = "select query"; + doReturn(mock(DataCommandResult.class)).when(spyCommand).select(query, null); + + spyCommand.query(query, null, false, null); + + verify(spyCommand).select(query, null); + } + + @Test + public void targetMemberIsSetIfMemberOptionsIsUsed() { + QueryCommand spyCommand = spy(command); + DistributedMember member = mock(DistributedMember.class); + String query = "select query"; + String memberName = "member"; + doReturn(member).when(spyCommand).getMember(memberName); + doReturn(mock(DataCommandResult.class)).when(spyCommand).select(query, member); + + spyCommand.query(query, null, false, memberName); + + verify(spyCommand).select(query, member); + } + + @Test + public void getQueryRegionsAssociatedMembersInvokedIfNoTargetProvided() { + QueryCommand spyCommand = spy(command); + InternalCache cache = mock(InternalCache.class); + Set<String> regionsInQuery = new HashSet<>(); + doReturn(new HashSet<>()).when(spyCommand).getQueryRegionsAssociatedMembers(cache, + regionsInQuery); + + spyCommand.getMembers(null, cache, regionsInQuery); + + verify(spyCommand).getQueryRegionsAssociatedMembers(cache, regionsInQuery); + } + +}