You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by jc...@apache.org on 2018/11/16 18:53:31 UTC
[geode] branch develop updated: GEODE-6025: add describe
data-source (#2864)
This is an automated email from the ASF dual-hosted git repository.
jchen21 pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push:
new 0c1f584 GEODE-6025: add describe data-source (#2864)
0c1f584 is described below
commit 0c1f5849c7961c6f75d329bc05d5aa5c56872e79
Author: Darrel Schneider <ds...@pivotal.io>
AuthorDate: Fri Nov 16 10:53:22 2018 -0800
GEODE-6025: add describe data-source (#2864)
In addition to adding the `describe data-source` gfsh command, the `create data-source` gfsh command and related tests have been moved to `geode-connectors` from `geode-core`
Co-authored-by: Darrel Schneider <ds...@pivotal.io>
Co-authored-by: Jianxia Chen <jc...@pivotal.io>
Co-authored-by: Scott Jewell <sj...@pivotal.io>
---
geode-connectors/build.gradle | 1 +
.../cli}/CreateDataSourceCommandDUnitTest.java | 2 +-
.../cli/DescribeDataSourceCommandDUnitTest.java | 114 ++++++
.../internal/cli}/CreateDataSourceCommand.java | 4 +-
.../internal/cli}/CreateDataSourceInterceptor.java | 3 +-
.../internal/cli/DescribeDataSourceCommand.java | 136 ++++++++
.../cli/converters/PoolPropertyConverter.java | 10 +-
.../org.springframework.shell.core.CommandMarker | 2 +
.../internal/cli}/CreateDataSourceCommandTest.java | 11 +-
.../cli}/CreateDataSourceInterceptorTest.java | 2 +-
.../cli/DescribeDataSourceCommandTest.java | 382 +++++++++++++++++++++
.../cli/commands/CommandAvailabilityIndicator.java | 1 -
.../cli/commands/UsernamePasswordInterceptor.java | 2 +-
13 files changed, 652 insertions(+), 18 deletions(-)
diff --git a/geode-connectors/build.gradle b/geode-connectors/build.gradle
index 71b3e44..4ad624b 100644
--- a/geode-connectors/build.gradle
+++ b/geode-connectors/build.gradle
@@ -75,6 +75,7 @@ dependencies {
distributedTestCompile('junit:junit:' + project.'junit.version')
distributedTestCompile('org.assertj:assertj-core:' + project.'assertj-core.version')
distributedTestCompile('org.mockito:mockito-core:2.19.1')
+ distributedTestRuntime('org.apache.derby:derby:' + project.'derby.version')
acceptanceTestCompile('com.github.stefanbirkner:system-rules:' + project.'system-rules.version') {
exclude module: 'junit-dep'
diff --git a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceCommandDUnitTest.java b/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceCommandDUnitTest.java
similarity index 98%
rename from geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceCommandDUnitTest.java
rename to geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceCommandDUnitTest.java
index 8dc4843..dd4169c 100644
--- a/geode-core/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceCommandDUnitTest.java
+++ b/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceCommandDUnitTest.java
@@ -13,7 +13,7 @@
* the License.
*/
-package org.apache.geode.management.internal.cli.commands;
+package org.apache.geode.connectors.jdbc.internal.cli;
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
diff --git a/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeDataSourceCommandDUnitTest.java b/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeDataSourceCommandDUnitTest.java
new file mode 100644
index 0000000..dc51f64
--- /dev/null
+++ b/geode-connectors/src/distributedTest/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeDataSourceCommandDUnitTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.connectors.jdbc.internal.cli;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Properties;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import org.apache.geode.management.internal.cli.result.model.InfoResultModel;
+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.rules.GfshCommandRule;
+
+public class DescribeDataSourceCommandDUnitTest {
+
+ private MemberVM locator, server;
+
+ @Rule
+ public ClusterStartupRule cluster = new ClusterStartupRule();
+
+ @Rule
+ public GfshCommandRule gfsh = new GfshCommandRule();
+
+ @Before
+ public void before() throws Exception {
+ locator = cluster.startLocatorVM(0);
+ server = cluster.startServerVM(1, new Properties(), locator.getPort());
+
+ gfsh.connectAndVerify(locator);
+ }
+
+ @Test
+ public void describeDataSourceForSimpleDataSource() {
+ gfsh.executeAndAssertThat(
+ "create data-source --name=simple --url=\"jdbc:derby:newDB;create=true\" --username=joe --password=myPassword")
+ .statusIsSuccess().tableHasColumnOnlyWithValues("Member", "server-1");
+
+ CommandResultAssert result = gfsh.executeAndAssertThat("describe data-source --name=simple");
+
+ result.statusIsSuccess()
+ .tableHasRowWithValues("Property", "Value", "name", "simple")
+ .tableHasRowWithValues("Property", "Value", "pooled", "false")
+ .tableHasRowWithValues("Property", "Value", "username", "joe")
+ .tableHasRowWithValues("Property", "Value", "url", "jdbc:derby:newDB;create=true");
+ assertThat(result.getResultModel().toString()).doesNotContain("myPassword");
+ }
+
+ @Test
+ public void describeDataSourceUsedByRegionsListsTheRegionsInOutput() {
+ gfsh.executeAndAssertThat(
+ "create data-source --name=simple --url=\"jdbc:derby:newDB;create=true\"")
+ .statusIsSuccess().tableHasColumnOnlyWithValues("Member", "server-1");
+ gfsh.executeAndAssertThat("create region --name=region1 --type=REPLICATE").statusIsSuccess();
+ gfsh.executeAndAssertThat("create region --name=region2 --type=PARTITION").statusIsSuccess();
+ gfsh.executeAndAssertThat(
+ "create jdbc-mapping --region=region1 --data-source=simple --pdx-name=myPdx");
+ gfsh.executeAndAssertThat(
+ "create jdbc-mapping --region=region2 --data-source=simple --pdx-name=myPdx");
+
+ CommandResultAssert result = gfsh.executeAndAssertThat("describe data-source --name=simple");
+
+ result.statusIsSuccess()
+ .tableHasRowWithValues("Property", "Value", "name", "simple")
+ .tableHasRowWithValues("Property", "Value", "pooled", "false")
+ .tableHasRowWithValues("Property", "Value", "url", "jdbc:derby:newDB;create=true");
+ InfoResultModel infoSection = result.getResultModel()
+ .getInfoSection(DescribeDataSourceCommand.REGIONS_USING_DATA_SOURCE_SECTION);
+ assertThat(new HashSet<>(infoSection.getContent()))
+ .isEqualTo(new HashSet<>(Arrays.asList("region1", "region2")));
+ }
+
+ @Test
+ public void describeDataSourceForPooledDataSource() {
+ gfsh.executeAndAssertThat(
+ "create data-source --name=pooled --pooled --url=\"jdbc:derby:newDB;create=true\" --pooled-data-source-factory-class=org.apache.geode.internal.jta.CacheJTAPooledDataSourceFactory --pool-properties={'name':'prop1','value':'value1'},{'name':'pool.prop2','value':'value2'}")
+ .statusIsSuccess().tableHasColumnOnlyWithValues("Member", "server-1");
+
+ gfsh.executeAndAssertThat("describe data-source --name=pooled").statusIsSuccess()
+ .tableHasRowWithValues("Property", "Value", "name", "pooled")
+ .tableHasRowWithValues("Property", "Value", "pooled", "true")
+ .tableHasRowWithValues("Property", "Value", "username", "")
+ .tableHasRowWithValues("Property", "Value", "url", "jdbc:derby:newDB;create=true")
+ .tableHasRowWithValues("Property", "Value", "pooled-data-source-factory-class",
+ "org.apache.geode.internal.jta.CacheJTAPooledDataSourceFactory")
+ .tableHasRowWithValues("Property", "Value", "prop1", "value1")
+ .tableHasRowWithValues("Property", "Value", "pool.prop2", "value2");
+ }
+
+ @Test
+ public void describeDataSourceDoesNotExist() {
+ gfsh.executeAndAssertThat("describe data-source --name=unknown").statusIsError()
+ .containsOutput("Data source: unknown not found");
+ }
+}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceCommand.java
similarity index 98%
rename from geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceCommand.java
rename to geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceCommand.java
index 7847700..345d182 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceCommand.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceCommand.java
@@ -12,7 +12,7 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.management.internal.cli.commands;
+package org.apache.geode.connectors.jdbc.internal.cli;
import java.util.List;
import java.util.Set;
@@ -74,7 +74,7 @@ public class CreateDataSourceCommand extends SingleGfshCommand {
@CliCommand(value = CREATE_DATA_SOURCE, help = CREATE_DATA_SOURCE__HELP)
@CliMetaData(relatedTopic = CliStrings.DEFAULT_TOPIC_GEODE,
- interceptor = "org.apache.geode.management.internal.cli.commands.CreateDataSourceInterceptor")
+ interceptor = "org.apache.geode.connectors.jdbc.internal.cli.CreateDataSourceInterceptor")
@ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
operation = ResourcePermission.Operation.MANAGE)
public ResultModel createJDNIBinding(
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceInterceptor.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceInterceptor.java
similarity index 94%
rename from geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceInterceptor.java
rename to geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceInterceptor.java
index 58343db..1c80ea6 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceInterceptor.java
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceInterceptor.java
@@ -14,9 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.geode.management.internal.cli.commands;
+package org.apache.geode.connectors.jdbc.internal.cli;
import org.apache.geode.management.internal.cli.GfshParseResult;
+import org.apache.geode.management.internal.cli.commands.UsernamePasswordInterceptor;
import org.apache.geode.management.internal.cli.result.model.ResultModel;
import org.apache.geode.management.internal.cli.shell.Gfsh;
diff --git a/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeDataSourceCommand.java b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeDataSourceCommand.java
new file mode 100644
index 0000000..611fe74
--- /dev/null
+++ b/geode-connectors/src/main/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeDataSourceCommand.java
@@ -0,0 +1,136 @@
+/*
+ * 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.connectors.jdbc.internal.cli;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.annotations.Experimental;
+import org.apache.geode.cache.configuration.CacheConfig;
+import org.apache.geode.cache.configuration.CacheElement;
+import org.apache.geode.cache.configuration.JndiBindingsType;
+import org.apache.geode.cache.configuration.RegionConfig;
+import org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping;
+import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.internal.cli.commands.CreateJndiBindingCommand.DATASOURCE_TYPE;
+import org.apache.geode.management.internal.cli.commands.InternalGfshCommand;
+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.cli.result.model.TabularResultModel;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+@Experimental
+public class DescribeDataSourceCommand extends InternalGfshCommand {
+ static final String DESCRIBE_DATA_SOURCE = "describe data-source";
+ private static final String DESCRIBE_DATA_SOURCE__HELP = EXPERIMENTAL +
+ "Describe the configuration of the given data source.";
+
+ static final String DATA_SOURCE_PROPERTIES_SECTION = "data-source-properties";
+ static final String REGIONS_USING_DATA_SOURCE_SECTION = "regions-using-data-source";
+
+ @CliCommand(value = DESCRIBE_DATA_SOURCE, help = DESCRIBE_DATA_SOURCE__HELP)
+ @CliMetaData
+ @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
+ operation = ResourcePermission.Operation.READ)
+ public ResultModel describeDataSource(@CliOption(key = "name", mandatory = true,
+ help = "Name of the data source to describe") String dataSourceName) {
+
+ ResultModel resultModel = new ResultModel();
+ resultModel.setHeader(EXPERIMENTAL);
+ TabularResultModel tabularData = resultModel.addTable(DATA_SOURCE_PROPERTIES_SECTION);
+
+ InternalConfigurationPersistenceService ccService = getConfigurationPersistenceService();
+ if (ccService == null) {
+ return ResultModel.createError("Cluster configuration service must be enabled.");
+ }
+ CacheConfig cacheConfig = ccService.getCacheConfig(null);
+ if (cacheConfig == null) {
+ return ResultModel.createError(String.format("Data source: %s not found", dataSourceName));
+ }
+
+ List<JndiBindingsType.JndiBinding> jndiBindings = cacheConfig.getJndiBindings();
+ JndiBindingsType.JndiBinding binding = jndiBindings.stream()
+ .filter(b -> b.getJndiName().equals(dataSourceName)).findFirst().orElse(null);
+ if (binding == null) {
+ return ResultModel.createError(String.format("Data source: %s not found", dataSourceName));
+ }
+ boolean pooled;
+ String type = binding.getType();
+ if (DATASOURCE_TYPE.SIMPLE.getType().equals(type)) {
+ pooled = false;
+ } else if (DATASOURCE_TYPE.POOLED.getType().equals(type)) {
+ pooled = true;
+ } else {
+ return ResultModel.createError(String.format("Unknown data source type: %s", type));
+ }
+
+ addTableRow(tabularData, CreateDataSourceCommand.NAME, binding.getJndiName());
+ addTableRow(tabularData, CreateDataSourceCommand.URL, binding.getConnectionUrl());
+ addTableRow(tabularData, CreateDataSourceCommand.USERNAME, binding.getUserName());
+ addTableRow(tabularData, CreateDataSourceCommand.POOLED, Boolean.toString(pooled));
+ if (pooled) {
+ addTableRow(tabularData, CreateDataSourceCommand.POOLED_DATA_SOURCE_FACTORY_CLASS,
+ binding.getConnPooledDatasourceClass());
+ for (JndiBindingsType.JndiBinding.ConfigProperty confProp : binding.getConfigProperties()) {
+ addTableRow(tabularData, confProp.getName(), confProp.getValue());
+ }
+ }
+
+ InfoResultModel regionsUsingSection = resultModel.addInfo(REGIONS_USING_DATA_SOURCE_SECTION);
+ List<String> regionsUsing = getRegionsThatUseDataSource(cacheConfig, dataSourceName);
+ regionsUsingSection.setHeader("Regions Using Data Source:");
+ if (regionsUsing.isEmpty()) {
+ regionsUsingSection.addLine("no regions are using " + dataSourceName);
+ } else {
+ regionsUsingSection.setContent(regionsUsing);
+ }
+
+ return resultModel;
+ }
+
+ List<String> getRegionsThatUseDataSource(CacheConfig cacheConfig, String dataSourceName) {
+ return cacheConfig.getRegions()
+ .stream()
+ .filter(regionConfig -> hasJdbcMappingThatUsesDataSource(regionConfig, dataSourceName))
+ .map(RegionConfig::getName)
+ .collect(Collectors.toList());
+ }
+
+ private boolean hasJdbcMappingThatUsesDataSource(RegionConfig regionConfig,
+ String dataSourceName) {
+ return regionConfig.getCustomRegionElements()
+ .stream()
+ .anyMatch(cacheElement -> isRegionMappingUsingDataSource(cacheElement, dataSourceName));
+ }
+
+ private boolean isRegionMappingUsingDataSource(CacheElement cacheElement, String dataSourceName) {
+ if (!(cacheElement instanceof RegionMapping)) {
+ return false;
+ }
+ RegionMapping regionMapping = (RegionMapping) cacheElement;
+ return dataSourceName.equals(regionMapping.getDataSourceName());
+ }
+
+ private void addTableRow(TabularResultModel table, String property, String value) {
+ table.accumulate("Property", property);
+ table.accumulate("Value", value != null ? value : "");
+ }
+}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/converters/PoolPropertyConverter.java b/geode-connectors/src/main/java/org/apache/geode/management/internal/cli/converters/PoolPropertyConverter.java
similarity index 83%
rename from geode-core/src/main/java/org/apache/geode/management/internal/cli/converters/PoolPropertyConverter.java
rename to geode-connectors/src/main/java/org/apache/geode/management/internal/cli/converters/PoolPropertyConverter.java
index 374c6f9..f5b7cd7 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/converters/PoolPropertyConverter.java
+++ b/geode-connectors/src/main/java/org/apache/geode/management/internal/cli/converters/PoolPropertyConverter.java
@@ -23,14 +23,14 @@ import org.springframework.shell.core.Completion;
import org.springframework.shell.core.Converter;
import org.springframework.shell.core.MethodTarget;
-import org.apache.geode.management.internal.cli.commands.CreateDataSourceCommand.PoolProperty;
+import org.apache.geode.connectors.jdbc.internal.cli.CreateDataSourceCommand;
/***
* Converter for CreateDataSourceCommand's --pool-properties option.
*
*/
public class PoolPropertyConverter
- implements Converter<PoolProperty> {
+ implements Converter<CreateDataSourceCommand.PoolProperty> {
private static ObjectMapper mapper = new ObjectMapper();
static {
@@ -39,14 +39,14 @@ public class PoolPropertyConverter
@Override
public boolean supports(Class<?> type, String optionContext) {
- return PoolProperty.class.isAssignableFrom(type);
+ return CreateDataSourceCommand.PoolProperty.class.isAssignableFrom(type);
}
@Override
- public PoolProperty convertFromText(String value,
+ public CreateDataSourceCommand.PoolProperty convertFromText(String value,
Class<?> targetType, String optionContext) {
try {
- return mapper.readValue(value, PoolProperty.class);
+ return mapper.readValue(value, CreateDataSourceCommand.PoolProperty.class);
} catch (IOException e) {
throw new IllegalArgumentException("invalid json: \"" + value + "\" details: " + e);
}
diff --git a/geode-connectors/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker b/geode-connectors/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker
index bf3e1eb..a6ae8aa 100644
--- a/geode-connectors/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker
+++ b/geode-connectors/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker
@@ -15,7 +15,9 @@
# limitations under the License.
#
# JDBC Connector Extension commands
+org.apache.geode.connectors.jdbc.internal.cli.CreateDataSourceCommand
org.apache.geode.connectors.jdbc.internal.cli.CreateMappingCommand
+org.apache.geode.connectors.jdbc.internal.cli.DescribeDataSourceCommand
org.apache.geode.connectors.jdbc.internal.cli.DestroyMappingCommand
org.apache.geode.connectors.jdbc.internal.cli.DescribeMappingCommand
org.apache.geode.connectors.jdbc.internal.cli.ListMappingCommand
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceCommandTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceCommandTest.java
similarity index 97%
rename from geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceCommandTest.java
rename to geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceCommandTest.java
index ea4e8d7..6f5f340 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceCommandTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceCommandTest.java
@@ -12,7 +12,7 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.management.internal.cli.commands;
+package org.apache.geode.connectors.jdbc.internal.cli;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -20,7 +20,6 @@ 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;
@@ -39,6 +38,7 @@ import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
import org.xml.sax.SAXException;
import org.apache.geode.cache.configuration.CacheConfig;
@@ -49,7 +49,6 @@ import org.apache.geode.distributed.internal.DistributionManager;
import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.management.internal.cli.GfshParseResult;
-import org.apache.geode.management.internal.cli.commands.CreateDataSourceCommand.PoolProperty;
import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
import org.apache.geode.management.internal.cli.functions.CreateJndiBindingFunction;
import org.apache.geode.test.junit.rules.GfshParserRule;
@@ -70,7 +69,7 @@ public class CreateDataSourceCommandTest {
public void setUp() throws Exception {
cache = mock(InternalCache.class);
when(cache.getDistributionManager()).thenReturn(mock(DistributionManager.class));
- command = spy(CreateDataSourceCommand.class);
+ command = Mockito.spy(CreateDataSourceCommand.class);
command.setCache(cache);
binding = new JndiBindingsType.JndiBinding();
@@ -101,8 +100,8 @@ public class CreateDataSourceCommandTest {
+ " --pooled --name=name --url=url "
+ "--pool-properties={'name':'name1','value':'value1'},{'name':'name2','value':'value2'}");
- PoolProperty[] poolProperties =
- (PoolProperty[]) result
+ CreateDataSourceCommand.PoolProperty[] poolProperties =
+ (CreateDataSourceCommand.PoolProperty[]) result
.getParamValue("pool-properties");
assertThat(poolProperties).hasSize(2);
assertThat(poolProperties[0].getName()).isEqualTo("name1");
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceInterceptorTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceInterceptorTest.java
similarity index 98%
rename from geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceInterceptorTest.java
rename to geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceInterceptorTest.java
index 83c40b7..145d021 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CreateDataSourceInterceptorTest.java
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/CreateDataSourceInterceptorTest.java
@@ -12,7 +12,7 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.apache.geode.management.internal.cli.commands;
+package org.apache.geode.connectors.jdbc.internal.cli;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
diff --git a/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeDataSourceCommandTest.java b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeDataSourceCommandTest.java
new file mode 100644
index 0000000..abba7a2
--- /dev/null
+++ b/geode-connectors/src/test/java/org/apache/geode/connectors/jdbc/internal/cli/DescribeDataSourceCommandTest.java
@@ -0,0 +1,382 @@
+/*
+ * 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.connectors.jdbc.internal.cli;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import 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.ClassRule;
+import org.junit.Test;
+
+import org.apache.geode.cache.configuration.CacheConfig;
+import org.apache.geode.cache.configuration.CacheElement;
+import org.apache.geode.cache.configuration.JndiBindingsType;
+import org.apache.geode.cache.configuration.JndiBindingsType.JndiBinding.ConfigProperty;
+import org.apache.geode.cache.configuration.RegionConfig;
+import org.apache.geode.connectors.jdbc.internal.configuration.RegionMapping;
+import org.apache.geode.distributed.internal.InternalConfigurationPersistenceService;
+import org.apache.geode.management.cli.Result.Status;
+import org.apache.geode.management.internal.cli.commands.CreateJndiBindingCommand.DATASOURCE_TYPE;
+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.cli.result.model.TabularResultModel;
+import org.apache.geode.test.junit.rules.GfshParserRule;
+
+public class DescribeDataSourceCommandTest {
+
+ @ClassRule
+ public static GfshParserRule gfsh = new GfshParserRule();
+
+ private DescribeDataSourceCommand command;
+
+ private JndiBindingsType.JndiBinding binding;
+ private List<JndiBindingsType.JndiBinding> bindings;
+ private InternalConfigurationPersistenceService clusterConfigService;
+ private CacheConfig cacheConfig;
+ private List<RegionConfig> regionConfigs;
+
+ private static String COMMAND = "describe data-source";
+ private static String DATA_SOURCE_NAME = "myDataSource";
+
+ @Before
+ public void setUp() {
+ command = spy(DescribeDataSourceCommand.class);
+
+ binding = new JndiBindingsType.JndiBinding();
+ binding.setJndiName(DATA_SOURCE_NAME);
+ binding.setType(DATASOURCE_TYPE.POOLED.getType());
+ bindings = new ArrayList<>();
+ clusterConfigService = mock(InternalConfigurationPersistenceService.class);
+ cacheConfig = mock(CacheConfig.class);
+ when(cacheConfig.getJndiBindings()).thenReturn(bindings);
+ bindings.add(binding);
+ regionConfigs = new ArrayList<>();
+ when(cacheConfig.getRegions()).thenReturn(regionConfigs);
+
+ doReturn(clusterConfigService).when(command).getConfigurationPersistenceService();
+ doReturn(cacheConfig).when(clusterConfigService).getCacheConfig(any());
+ }
+
+ @Test
+ public void missingMandatory() {
+ gfsh.executeAndAssertThat(command, COMMAND).statusIsError()
+ .containsOutput("Invalid command: describe data-source");
+ }
+
+ @Test
+ public void nameWorks() {
+ gfsh.executeAndAssertThat(command, COMMAND + " --name=" + DATA_SOURCE_NAME).statusIsSuccess();
+ }
+
+ @Test
+ public void describeDataSourceWithNoClusterConfigurationServerFails() {
+ doReturn(null).when(command).getConfigurationPersistenceService();
+
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ assertThat(result.getStatus()).isEqualTo(Status.ERROR);
+ assertThat(result.toString()).contains("Cluster configuration service must be enabled.");
+ }
+
+ @Test
+ public void describeDataSourceWithNoClusterConfigFails() {
+ doReturn(null).when(clusterConfigService).getCacheConfig(any());
+
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ assertThat(result.getStatus()).isEqualTo(Status.ERROR);
+ assertThat(result.toString()).contains("Data source: " + DATA_SOURCE_NAME + " not found");
+ }
+
+ @Test
+ public void describeDataSourceWithWrongNameFails() {
+ ResultModel result = command.describeDataSource("bogusName");
+
+ assertThat(result.getStatus()).isEqualTo(Status.ERROR);
+ assertThat(result.toString()).contains("Data source: bogusName not found");
+ }
+
+ @Test
+ public void describeDataSourceWithUnsupportedTypeFails() {
+ binding.setType(DATASOURCE_TYPE.MANAGED.getType());
+
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ assertThat(result.getStatus()).isEqualTo(Status.ERROR);
+ assertThat(result.toString()).contains("Unknown data source type: ManagedDataSource");
+ }
+
+ @Test
+ public void describeDataSourceWithSimpleTypeReturnsPooledFalse() {
+ binding.setType(DATASOURCE_TYPE.SIMPLE.getType());
+
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ TabularResultModel section =
+ result.getTableSection(DescribeDataSourceCommand.DATA_SOURCE_PROPERTIES_SECTION);
+ assertThat(section.getValuesInRow(3)).isEqualTo(Arrays.asList("pooled", "false"));
+ }
+
+ @Test
+ public void describeDataSourceWithPooledTypeReturnsPooledTrue() {
+ binding.setType(DATASOURCE_TYPE.POOLED.getType());
+
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ TabularResultModel section =
+ result.getTableSection(DescribeDataSourceCommand.DATA_SOURCE_PROPERTIES_SECTION);
+ assertThat(section.getValuesInRow(3)).isEqualTo(Arrays.asList("pooled", "true"));
+ }
+
+ @Test
+ public void describeDataSourceTypeReturnsName() {
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ TabularResultModel section =
+ result.getTableSection(DescribeDataSourceCommand.DATA_SOURCE_PROPERTIES_SECTION);
+ assertThat(section.getValuesInRow(0)).isEqualTo(Arrays.asList("name", DATA_SOURCE_NAME));
+ }
+
+ @Test
+ public void describeDataSourceWithUrlReturnsUrl() {
+ binding.setConnectionUrl("myUrl");
+
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ TabularResultModel section =
+ result.getTableSection(DescribeDataSourceCommand.DATA_SOURCE_PROPERTIES_SECTION);
+ assertThat(section.getValuesInRow(1)).isEqualTo(Arrays.asList("url", "myUrl"));
+ }
+
+ @Test
+ public void describeDataSourceWithUsernameReturnsUsername() {
+ binding.setUserName("myUserName");
+
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ TabularResultModel section =
+ result.getTableSection(DescribeDataSourceCommand.DATA_SOURCE_PROPERTIES_SECTION);
+ assertThat(section.getValuesInRow(2)).isEqualTo(Arrays.asList("username", "myUserName"));
+ }
+
+ @Test
+ public void describeDataSourceWithPooledDataSourceFactoryClassShowsItInTheResult() {
+ binding.setType(DATASOURCE_TYPE.POOLED.getType());
+ binding.setConnPooledDatasourceClass("myPooledDataSourceFactoryClass");
+
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ TabularResultModel section =
+ result.getTableSection(DescribeDataSourceCommand.DATA_SOURCE_PROPERTIES_SECTION);
+ assertThat(section.getValuesInRow(4)).isEqualTo(
+ Arrays.asList("pooled-data-source-factory-class", "myPooledDataSourceFactoryClass"));
+ }
+
+ @Test
+ public void describeDataSourceWithPasswordDoesNotShowPasswordInResult() {
+ binding.setType(DATASOURCE_TYPE.POOLED.getType());
+ binding.setPassword("myPassword");
+
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ assertThat(result.toString()).doesNotContain("myPassword");
+ }
+
+ @Test
+ public void describeDataSourceWithPoolPropertiesDoesNotShowsItInTheResult() {
+ binding.setType(DATASOURCE_TYPE.SIMPLE.getType());
+ List<ConfigProperty> configProperties = binding.getConfigProperties();
+ configProperties.add(new ConfigProperty("name1", "value1"));
+
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ assertThat(result.toString()).doesNotContain("name1");
+ assertThat(result.toString()).doesNotContain("value1");
+ }
+
+ @Test
+ public void describeDataSourceWithPoolPropertiesShowsItInTheResult() {
+ binding.setType(DATASOURCE_TYPE.POOLED.getType());
+ List<ConfigProperty> configProperties = binding.getConfigProperties();
+ configProperties.add(new ConfigProperty("name1", "value1"));
+ configProperties.add(new ConfigProperty("name2", "value2"));
+
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ TabularResultModel section =
+ result.getTableSection(DescribeDataSourceCommand.DATA_SOURCE_PROPERTIES_SECTION);
+ assertThat(section.getValuesInRow(5)).isEqualTo(Arrays.asList("name1", "value1"));
+ assertThat(section.getValuesInRow(6)).isEqualTo(Arrays.asList("name2", "value2"));
+ }
+
+ @Test
+ public void getRegionsThatUseDataSourceGivenNoRegionsReturnsEmptyList() {
+ regionConfigs.clear();
+
+ List<String> result = command.getRegionsThatUseDataSource(cacheConfig, "");
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void getRegionsThatUseDataSourceGivenRegionConfigWithNoCustomRegionElementsReturnsEmptyList() {
+ RegionConfig regionConfig = mock(RegionConfig.class);
+ when(regionConfig.getCustomRegionElements()).thenReturn(Collections.emptyList());
+ regionConfigs.add(regionConfig);
+
+ List<String> result = command.getRegionsThatUseDataSource(cacheConfig, "");
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void getRegionsThatUseDataSourceGivenRegionConfigWithNonRegionMappingElementReturnsEmptyList() {
+ RegionConfig regionConfig = mock(RegionConfig.class);
+ when(regionConfig.getCustomRegionElements())
+ .thenReturn(Collections.singletonList(mock(CacheElement.class)));
+ regionConfigs.add(regionConfig);
+
+ List<String> result = command.getRegionsThatUseDataSource(cacheConfig, "");
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void getRegionsThatUseDataSourceGivenRegionConfigWithRegionMappingForOtherDataSourceReturnsEmptyList() {
+ RegionConfig regionConfig = mock(RegionConfig.class);
+ when(regionConfig.getCustomRegionElements())
+ .thenReturn(Collections.singletonList(mock(RegionMapping.class)));
+ regionConfigs.add(regionConfig);
+
+ List<String> result = command.getRegionsThatUseDataSource(cacheConfig, "bogusDataSource");
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void getRegionsThatUseDataSourceGivenRegionConfigWithRegionMappingForDataSourceReturnsRegionName() {
+ RegionConfig regionConfig = mock(RegionConfig.class);
+ when(regionConfig.getName()).thenReturn("regionName");
+ RegionMapping regionMapping = mock(RegionMapping.class);
+ when(regionMapping.getDataSourceName()).thenReturn("dataSourceName");
+ when(regionConfig.getCustomRegionElements())
+ .thenReturn(Collections.singletonList(regionMapping));
+ regionConfigs.add(regionConfig);
+
+ List<String> result = command.getRegionsThatUseDataSource(cacheConfig, "dataSourceName");
+
+ assertThat(result).isEqualTo(Collections.singletonList("regionName"));
+ }
+
+ @Test
+ public void getRegionsThatUseDataSourceGivenMultipleRegionConfigsReturnsAllRegionNames() {
+ RegionMapping regionMapping;
+ {
+ RegionConfig regionConfig1 = mock(RegionConfig.class, "regionConfig1");
+ when(regionConfig1.getName()).thenReturn("regionName1");
+ regionMapping = mock(RegionMapping.class, "regionMapping1");
+ when(regionMapping.getDataSourceName()).thenReturn("dataSourceName");
+ when(regionConfig1.getCustomRegionElements())
+ .thenReturn(Arrays.asList(regionMapping));
+ regionConfigs.add(regionConfig1);
+ }
+ {
+ RegionConfig regionConfig2 = mock(RegionConfig.class, "regionConfig2");
+ when(regionConfig2.getName()).thenReturn("regionName2");
+ regionMapping = mock(RegionMapping.class, "regionMapping2");
+ when(regionMapping.getDataSourceName()).thenReturn("otherDataSourceName");
+ when(regionConfig2.getCustomRegionElements())
+ .thenReturn(Arrays.asList(regionMapping));
+ regionConfigs.add(regionConfig2);
+ }
+ {
+ RegionConfig regionConfig3 = mock(RegionConfig.class, "regionConfig3");
+ when(regionConfig3.getName()).thenReturn("regionName3");
+ regionMapping = mock(RegionMapping.class, "regionMapping3");
+ when(regionMapping.getDataSourceName()).thenReturn("dataSourceName");
+ when(regionConfig3.getCustomRegionElements())
+ .thenReturn(Arrays.asList(regionMapping));
+ regionConfigs.add(regionConfig3);
+ }
+
+ List<String> result = command.getRegionsThatUseDataSource(cacheConfig, "dataSourceName");
+
+ assertThat(result).isEqualTo(Arrays.asList("regionName1", "regionName3"));
+ }
+
+ @Test
+ public void describeDataSourceWithRegionsUsingItReturnsResultWithNoRegionsUsingIt() {
+ RegionConfig regionConfig = mock(RegionConfig.class);
+ when(regionConfig.getCustomRegionElements())
+ .thenReturn(Collections.singletonList(mock(RegionMapping.class)));
+ regionConfigs.add(regionConfig);
+
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ InfoResultModel regionsUsingSection = (InfoResultModel) result
+ .getSection(DescribeDataSourceCommand.REGIONS_USING_DATA_SOURCE_SECTION);
+ assertThat(regionsUsingSection.getContent())
+ .isEqualTo(Arrays.asList("no regions are using " + DATA_SOURCE_NAME));
+ }
+
+ @Test
+ public void describeDataSourceWithRegionsUsingItReturnsResultWithRegionNames() {
+ RegionMapping regionMapping;
+ {
+ RegionConfig regionConfig1 = mock(RegionConfig.class, "regionConfig1");
+ when(regionConfig1.getName()).thenReturn("regionName1");
+ regionMapping = mock(RegionMapping.class, "regionMapping1");
+ when(regionMapping.getDataSourceName()).thenReturn(DATA_SOURCE_NAME);
+ when(regionConfig1.getCustomRegionElements())
+ .thenReturn(Arrays.asList(regionMapping));
+ regionConfigs.add(regionConfig1);
+ }
+ {
+ RegionConfig regionConfig2 = mock(RegionConfig.class, "regionConfig2");
+ when(regionConfig2.getName()).thenReturn("regionName2");
+ regionMapping = mock(RegionMapping.class, "regionMapping2");
+ when(regionMapping.getDataSourceName()).thenReturn("otherDataSourceName");
+ when(regionConfig2.getCustomRegionElements())
+ .thenReturn(Arrays.asList(regionMapping));
+ regionConfigs.add(regionConfig2);
+ }
+ {
+ RegionConfig regionConfig3 = mock(RegionConfig.class, "regionConfig3");
+ when(regionConfig3.getName()).thenReturn("regionName3");
+ regionMapping = mock(RegionMapping.class, "regionMapping3");
+ when(regionMapping.getDataSourceName()).thenReturn(DATA_SOURCE_NAME);
+ when(regionConfig3.getCustomRegionElements())
+ .thenReturn(Arrays.asList(regionMapping));
+ regionConfigs.add(regionConfig3);
+ }
+
+ ResultModel result = command.describeDataSource(DATA_SOURCE_NAME);
+
+ InfoResultModel regionsUsingSection = (InfoResultModel) result
+ .getSection(DescribeDataSourceCommand.REGIONS_USING_DATA_SOURCE_SECTION);
+ assertThat(regionsUsingSection.getContent())
+ .isEqualTo(Arrays.asList("regionName1", "regionName3"));
+ }
+}
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CommandAvailabilityIndicator.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CommandAvailabilityIndicator.java
index 516ede4..a2d6049 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CommandAvailabilityIndicator.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CommandAvailabilityIndicator.java
@@ -51,7 +51,6 @@ public class CommandAvailabilityIndicator extends GfshCommand {
CliStrings.DESTROY_GATEWAYSENDER, AlterAsyncEventQueueCommand.COMMAND_NAME,
DestroyAsyncEventQueueCommand.DESTROY_ASYNC_EVENT_QUEUE,
DestroyGatewayReceiverCommand.DESTROY_GATEWAYRECEIVER,
- CreateDataSourceCommand.CREATE_DATA_SOURCE,
CreateJndiBindingCommand.CREATE_JNDIBINDING, DestroyJndiBindingCommand.DESTROY_JNDIBINDING,
DescribeJndiBindingCommand.DESCRIBE_JNDI_BINDING, ListJndiBindingCommand.LIST_JNDIBINDING})
public boolean available() {
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/UsernamePasswordInterceptor.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/UsernamePasswordInterceptor.java
index c3a5d1b..195ab85 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/UsernamePasswordInterceptor.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/UsernamePasswordInterceptor.java
@@ -30,7 +30,7 @@ public class UsernamePasswordInterceptor extends AbstractCliAroundInterceptor {
}
// Constructor for unit test
- UsernamePasswordInterceptor(Gfsh gfsh) {
+ public UsernamePasswordInterceptor(Gfsh gfsh) {
this.gfsh = gfsh;
}