This is an automated email from the ASF dual-hosted git repository.
nizhikov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 9186d7576e3 IGNITE-23113 [ducktests] Add Thin JDBC driver support
(#11527)
9186d7576e3 is described below
commit 9186d7576e33303c4857eb06115e9f993e58be59
Author: Sergey Korotkov <[email protected]>
AuthorDate: Wed Sep 11 21:41:40 2024 +0700
IGNITE-23113 [ducktests] Add Thin JDBC driver support (#11527)
---
.../tests/jdbc/JdbcThinSelfTestApplication.java | 124 +++++++++++++++++++++
.../ducktest/utils/IgniteAwareApplication.java | 4 +
.../utils/IgniteAwareApplicationService.java | 12 +-
.../tests/ignitetest/services/utils/__init__.py | 1 +
.../ignitetest/services/utils/config_template.py | 9 ++
.../ignitetest/services/utils/ignite_aware.py | 3 +-
.../utils/ignite_configuration/__init__.py | 32 ++++++
.../tests/ignitetest/services/utils/ignite_spec.py | 13 ++-
.../tests/ignitetest/services/utils/path.py | 9 ++
.../utils/templates/thin_jdbc_config.xml.j2 | 46 ++++++++
.../tests/ignitetest/tests/jdbc_thin_test.py | 66 +++++++++++
11 files changed, 314 insertions(+), 5 deletions(-)
diff --git
a/modules/ducktests/src/main/java/org/apache/ignite/internal/ducktest/tests/jdbc/JdbcThinSelfTestApplication.java
b/modules/ducktests/src/main/java/org/apache/ignite/internal/ducktest/tests/jdbc/JdbcThinSelfTestApplication.java
new file mode 100644
index 00000000000..98ca821f874
--- /dev/null
+++
b/modules/ducktests/src/main/java/org/apache/ignite/internal/ducktest/tests/jdbc/JdbcThinSelfTestApplication.java
@@ -0,0 +1,124 @@
+/*
+ * 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.ignite.internal.ducktest.tests.jdbc;
+
+import java.math.BigDecimal;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import com.fasterxml.jackson.databind.JsonNode;
+import org.apache.ignite.internal.ducktest.utils.IgniteAwareApplication;
+
+/**
+ * Simple application working via the Thin JDBC driver.
+ */
+public class JdbcThinSelfTestApplication extends IgniteAwareApplication {
+ /** */
+ private static final BigDecimal DECIMAL_VALUE1 = BigDecimal.valueOf(762,
2);
+
+ /** */
+ private static final BigDecimal DECIMAL_VALUE2 = BigDecimal.valueOf(545,
2);
+
+ /** */
+ private static final String VARCHAR_VALUE = "ak";
+
+ /** {@inheritDoc} */
+ @Override public void run(JsonNode jsonNode) throws SQLException {
+ markInitialized();
+
+ try (Connection conn = thinJdbcDataSource.getConnection()) {
+ createTable(conn);
+
+ insertRow(conn);
+
+ selectRow(conn);
+
+ updateRow(conn);
+
+ deleteRow(conn);
+
+ dropTable(conn);
+
+ markFinished();
+ }
+ }
+
+ /** */
+ private void createTable(Connection conn) throws SQLException {
+ conn.createStatement().execute("CREATE TABLE IF NOT EXISTS table(id
INT, strVal VARCHAR, decVal DECIMAL, PRIMARY KEY(id)) ");
+ }
+
+ /** */
+ private void insertRow(Connection conn) throws SQLException {
+ PreparedStatement insertStatement = conn.prepareStatement("INSERT INTO
table(id, strVal, decVal) VALUES(?, ?, ?)");
+
+ insertStatement.setInt(1, 1);
+ insertStatement.setString(2, VARCHAR_VALUE);
+ insertStatement.setBigDecimal(3, DECIMAL_VALUE1);
+
+ insertStatement.execute();
+ }
+
+ /** */
+ private void selectRow(Connection conn) throws SQLException {
+ PreparedStatement selectStatement = conn.prepareStatement("SELECT *
FROM table WHERE id = ?");
+
+ selectStatement.setInt(1, 1);
+
+ ResultSet resultSet = selectStatement.executeQuery();
+
+ if (!resultSet.next())
+ markBroken(new RuntimeException("ResultSet is empty."));
+
+ int resultId = resultSet.getInt("id");
+ String resultStr = resultSet.getString("strVal");
+ BigDecimal resultDecimal = resultSet.getBigDecimal("decVal");
+
+ if (1 != resultId || !VARCHAR_VALUE.equals(resultStr) ||
DECIMAL_VALUE1.compareTo(resultDecimal) != 0)
+ throw new RuntimeException("Wrong row selected: " +
+ "expected [id=1, strVal=" + VARCHAR_VALUE + ", decVal=" +
DECIMAL_VALUE1 + "], " +
+ "actual [id=" + resultId + ", strVal=" + resultStr + ",
decVal=" + resultDecimal + "].");
+ }
+
+ /** */
+ private void updateRow(Connection conn) throws SQLException {
+ PreparedStatement selectStatement = conn.prepareStatement("UPDATE
table SET decVal = ? WHERE id = ?");
+
+ selectStatement.setBigDecimal(1, DECIMAL_VALUE2);
+ selectStatement.setInt(2, 1);
+
+ if (1 != selectStatement.executeUpdate())
+ throw new RuntimeException("Row wasn't updated.");
+ }
+
+ /** */
+ private void deleteRow(Connection conn) throws SQLException {
+ PreparedStatement selectStatement = conn.prepareStatement("DELETE FROM
table WHERE id = ?");
+
+ selectStatement.setInt(1, 1);
+
+ if (1 != selectStatement.executeUpdate())
+ throw new RuntimeException("Row wasn't deleted.");
+ }
+
+ /** */
+ private void dropTable(Connection conn) throws SQLException {
+ conn.createStatement().execute("DROP TABLE IF EXISTS table");
+ }
+}
diff --git
a/modules/ducktests/src/main/java/org/apache/ignite/internal/ducktest/utils/IgniteAwareApplication.java
b/modules/ducktests/src/main/java/org/apache/ignite/internal/ducktest/utils/IgniteAwareApplication.java
index 4d6c0ef086b..6157c94b0ac 100644
---
a/modules/ducktests/src/main/java/org/apache/ignite/internal/ducktest/utils/IgniteAwareApplication.java
+++
b/modules/ducktests/src/main/java/org/apache/ignite/internal/ducktest/utils/IgniteAwareApplication.java
@@ -21,6 +21,7 @@ import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteJdbcThinDataSource;
import org.apache.ignite.client.IgniteClient;
import org.apache.ignite.cluster.ClusterState;
import org.apache.ignite.internal.IgniteEx;
@@ -71,6 +72,9 @@ public abstract class IgniteAwareApplication {
/** Client. */
protected IgniteClient client;
+ /** Thin JDBC DataSource. */
+ protected IgniteJdbcThinDataSource thinJdbcDataSource;
+
/** Cfg path. */
protected String cfgPath;
diff --git
a/modules/ducktests/src/main/java/org/apache/ignite/internal/ducktest/utils/IgniteAwareApplicationService.java
b/modules/ducktests/src/main/java/org/apache/ignite/internal/ducktest/utils/IgniteAwareApplicationService.java
index 19b13a151b2..ddb0ef191c5 100644
---
a/modules/ducktests/src/main/java/org/apache/ignite/internal/ducktest/utils/IgniteAwareApplicationService.java
+++
b/modules/ducktests/src/main/java/org/apache/ignite/internal/ducktest/utils/IgniteAwareApplicationService.java
@@ -47,7 +47,10 @@ public class IgniteAwareApplicationService {
THIN_CLIENT,
/** Run application without precreated connections. */
- NONE
+ NONE,
+
+ /** Run application with the precreated thin JDBC data source. */
+ THIN_JDBC
}
/**
@@ -106,6 +109,13 @@ public class IgniteAwareApplicationService {
}
else if (svcType == IgniteServiceType.NONE)
app.start(jsonNode);
+ else if (svcType == IgniteServiceType.THIN_JDBC) {
+ log.info("Create thin jdbc ignite data source...");
+
+ app.thinJdbcDataSource = IgnitionEx.loadSpringBean(cfgPath,
"thin.jdbc.cfg");
+
+ app.start(jsonNode);
+ }
else
throw new IllegalArgumentException("Unknown service type " +
svcType);
}
diff --git a/modules/ducktests/tests/ignitetest/services/utils/__init__.py
b/modules/ducktests/tests/ignitetest/services/utils/__init__.py
index c2830bce18a..efe71e8ad11 100644
--- a/modules/ducktests/tests/ignitetest/services/utils/__init__.py
+++ b/modules/ducktests/tests/ignitetest/services/utils/__init__.py
@@ -29,3 +29,4 @@ class IgniteServiceType(IntEnum):
NODE = 0
THIN_CLIENT = 1
NONE = 2
+ THIN_JDBC = 3
diff --git
a/modules/ducktests/tests/ignitetest/services/utils/config_template.py
b/modules/ducktests/tests/ignitetest/services/utils/config_template.py
index 0af5f7cd77b..16a6a9a3533 100644
--- a/modules/ducktests/tests/ignitetest/services/utils/config_template.py
+++ b/modules/ducktests/tests/ignitetest/services/utils/config_template.py
@@ -24,6 +24,7 @@ IGNITE_TEMPLATE_PATH =
os.path.join(os.path.dirname(os.path.abspath(__file__)),
ZK_TEMPLATE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)),
"..", "zk", "templates")
DEFAULT_IGNITE_CONF = "ignite.xml.j2"
DEFAULT_THIN_CLIENT_CONF = "thin_client_config.xml.j2"
+DEFAULT_THIN_JDBC_CONF = "thin_jdbc_config.xml.j2"
DEFAULT_LOG4J2_CONF = "log4j2.xml.j2"
TEMPLATE_PATHES = [IGNITE_TEMPLATE_PATH, ZK_TEMPLATE_PATH]
@@ -85,6 +86,14 @@ class IgniteThinClientConfigTemplate(ConfigTemplate):
super().__init__(path)
+class IgniteThinJdbcConfigTemplate(ConfigTemplate):
+ """
+ Ignite client node configuration.
+ """
+ def __init__(self, path=DEFAULT_THIN_JDBC_CONF):
+ super().__init__(path)
+
+
class IgniteLoggerConfigTemplate(ConfigTemplate):
"""
Ignite logger configuration.
diff --git a/modules/ducktests/tests/ignitetest/services/utils/ignite_aware.py
b/modules/ducktests/tests/ignitetest/services/utils/ignite_aware.py
index 0a0b581f301..b6e2fe05e14 100644
--- a/modules/ducktests/tests/ignitetest/services/utils/ignite_aware.py
+++ b/modules/ducktests/tests/ignitetest/services/utils/ignite_aware.py
@@ -101,7 +101,8 @@ class IgniteAwareService(BackgroundThreadService,
IgnitePathAware, JvmProcessMix
"""
Awaits start finished.
"""
- if self.config.service_type in (IgniteServiceType.NONE,
IgniteServiceType.THIN_CLIENT):
+ if self.config.service_type in (IgniteServiceType.NONE,
IgniteServiceType.THIN_CLIENT,
+ IgniteServiceType.THIN_JDBC):
return
self.logger.info("Waiting for IgniteAware(s) to start ...")
diff --git
a/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/__init__.py
b/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/__init__.py
index 6f83f603e04..1fdec71e3b4 100644
---
a/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/__init__.py
+++
b/modules/ducktests/tests/ignitetest/services/utils/ignite_configuration/__init__.py
@@ -166,3 +166,35 @@ class IgniteThinClientConfiguration(NamedTuple):
Application mode.
"""
return IgniteServiceType.THIN_CLIENT
+
+
+class IgniteThinJdbcConfiguration(NamedTuple):
+ addresses: list = []
+ version: IgniteVersion = DEV_BRANCH
+ ssl_params: SslParams = None
+ username: str = None
+ password: str = None
+
+ def prepare_ssl(self, test_globals, shared_root):
+ """
+ Updates ssl configuration from globals.
+ """
+ ssl_params = None
+ if self.ssl_params is None and is_ssl_enabled(test_globals):
+ ssl_params = get_ssl_params(test_globals, shared_root,
IGNITE_CLIENT_ALIAS)
+ if ssl_params:
+ return self._replace(ssl_params=ssl_params)
+ return self
+
+ def prepare_for_env(self, cluster, node):
+ """
+ Updates configuration based on current environment.
+ """
+ return self
+
+ @property
+ def service_type(self):
+ """
+ Application mode.
+ """
+ return IgniteServiceType.THIN_JDBC
diff --git a/modules/ducktests/tests/ignitetest/services/utils/ignite_spec.py
b/modules/ducktests/tests/ignitetest/services/utils/ignite_spec.py
index e8c2c036b8b..7cb60371a04 100644
--- a/modules/ducktests/tests/ignitetest/services/utils/ignite_spec.py
+++ b/modules/ducktests/tests/ignitetest/services/utils/ignite_spec.py
@@ -29,7 +29,7 @@ from itertools import chain
from ignitetest.services.utils import IgniteServiceType
from ignitetest.services.utils.config_template import
IgniteClientConfigTemplate, IgniteServerConfigTemplate, \
- IgniteLoggerConfigTemplate, IgniteThinClientConfigTemplate
+ IgniteLoggerConfigTemplate, IgniteThinClientConfigTemplate,
IgniteThinJdbcConfigTemplate
from ignitetest.services.utils.jvm_utils import create_jvm_settings,
merge_jvm_settings
from ignitetest.services.utils.path import get_home_dir, IgnitePathAware
from ignitetest.services.utils.ssl.ssl_params import is_ssl_enabled
@@ -142,6 +142,9 @@ class IgniteSpec(metaclass=ABCMeta):
if self.service.config.service_type == IgniteServiceType.THIN_CLIENT:
config_templates.append((IgnitePathAware.IGNITE_THIN_CLIENT_CONFIG_NAME,
IgniteThinClientConfigTemplate()))
+ if self.service.config.service_type == IgniteServiceType.THIN_JDBC:
+
config_templates.append((IgnitePathAware.IGNITE_THIN_JDBC_CONFIG_NAME,
IgniteThinJdbcConfigTemplate()))
+
return config_templates
def extend_config(self, config):
@@ -355,5 +358,9 @@ class IgniteApplicationSpec(IgniteSpec):
return cmd
def config_file_path(self):
- return self.service.config_file if self.service.config.service_type ==
IgniteServiceType.NODE \
- else self.service.thin_client_config_file
+ if self.service.config.service_type == IgniteServiceType.NODE:
+ return self.service.config_file
+ elif self.service.config.service_type == IgniteServiceType.THIN_CLIENT:
+ return self.service.thin_client_config_file
+ else:
+ return self.service.thin_jdbc_config_file
diff --git a/modules/ducktests/tests/ignitetest/services/utils/path.py
b/modules/ducktests/tests/ignitetest/services/utils/path.py
index a1676d5887a..3bc02b32c80 100644
--- a/modules/ducktests/tests/ignitetest/services/utils/path.py
+++ b/modules/ducktests/tests/ignitetest/services/utils/path.py
@@ -173,6 +173,8 @@ class IgnitePathAware(PathAware, metaclass=ABCMeta):
IGNITE_THIN_CLIENT_CONFIG_NAME = "ignite-thin-config.xml"
+ IGNITE_THIN_JDBC_CONFIG_NAME = "ignite-thin-jdbc-config.xml"
+
IGNITE_LOG_CONFIG_NAME = "ignite-ducktape-log4j2.xml"
@property
@@ -189,6 +191,13 @@ class IgnitePathAware(PathAware, metaclass=ABCMeta):
"""
return os.path.join(self.config_dir,
IgnitePathAware.IGNITE_THIN_CLIENT_CONFIG_NAME)
+ @property
+ def thin_jdbc_config_file(self):
+ """
+ :return: path to thin JDBC driver config file
+ """
+ return os.path.join(self.config_dir,
IgnitePathAware.IGNITE_THIN_JDBC_CONFIG_NAME)
+
@property
def log_config_file(self):
"""
diff --git
a/modules/ducktests/tests/ignitetest/services/utils/templates/thin_jdbc_config.xml.j2
b/modules/ducktests/tests/ignitetest/services/utils/templates/thin_jdbc_config.xml.j2
new file mode 100644
index 00000000000..0c72cddc362
--- /dev/null
+++
b/modules/ducktests/tests/ignitetest/services/utils/templates/thin_jdbc_config.xml.j2
@@ -0,0 +1,46 @@
+{#
+ 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.
+#}
+
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
+ <bean class="org.apache.ignite.IgniteJdbcThinDataSource"
id="thin.jdbc.cfg">
+ <property name="addresses">
+ <list>
+ {% for address in config.addresses %}
+ <value>{{ address }}</value>
+ {% endfor %}
+ </list>
+ </property>
+
+ {% if config.username %}
+ <property name="username" value="{{ config.username }}"/>
+ <property name="password" value="{{ config.password }}"/>
+ {% endif %}
+
+ {% if config.ssl_params %}
+ <property name="sslMode" value="require"/>
+ <property name="sslClientCertificateKeyStoreUrl" value="{{
config.ssl_params.key_store_path }}"/>
+ <property name="sslClientCertificateKeyStorePassword" value="{{
config.ssl_params.key_store_password }}"/>
+ <property name="sslTrustCertificateKeyStoreUrl" value="{{
config.ssl_params.trust_store_path }}"/>
+ <property name="sslTrustCertificateKeyStorePassword" value="{{
config.ssl_params.trust_store_password }}"/>
+ {% endif %}
+ </bean>
+</beans>
diff --git a/modules/ducktests/tests/ignitetest/tests/jdbc_thin_test.py
b/modules/ducktests/tests/ignitetest/tests/jdbc_thin_test.py
new file mode 100644
index 00000000000..766ca010261
--- /dev/null
+++ b/modules/ducktests/tests/ignitetest/tests/jdbc_thin_test.py
@@ -0,0 +1,66 @@
+# 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.
+
+"""
+This module contains Thin JDBC driver tests.
+"""
+
+from ignitetest.services.ignite import IgniteService
+from ignitetest.services.ignite_app import IgniteApplicationService
+from ignitetest.services.utils.control_utility import ControlUtility
+from ignitetest.services.utils.ignite_configuration import
IgniteConfiguration, IgniteThinJdbcConfiguration
+from ignitetest.services.utils.ssl.client_connector_configuration import
ClientConnectorConfiguration
+from ignitetest.utils import cluster, ignite_versions
+from ignitetest.utils.ignite_test import IgniteTest
+from ignitetest.utils.version import DEV_BRANCH, LATEST, IgniteVersion
+
+
+class JdbcThinTest(IgniteTest):
+ """
+ Thin JDBC driver test.
+ """
+ @cluster(num_nodes=2)
+ @ignite_versions(str(DEV_BRANCH), str(LATEST),
version_prefix="server_version")
+ @ignite_versions(str(DEV_BRANCH), str(LATEST),
version_prefix="thin_jdbc_version")
+ def test_simple_insert_select(self, server_version, thin_jdbc_version):
+ """
+ Smoke test ensuring the Thin JDBC driver just works doing simple SQL
queries
+ and that the compationility between Ignite versions is preserved.
+ """
+ server_config = IgniteConfiguration(
+ version=IgniteVersion(server_version),
+ client_connector_configuration=ClientConnectorConfiguration())
+
+ ignite = IgniteService(self.test_context, server_config, 1)
+
+ ignite.start()
+
+ ControlUtility(ignite).activate()
+
+ address = ignite.nodes[0].account.hostname + ":" +
str(server_config.client_connector_configuration.port)
+
+ app = IgniteApplicationService(
+ self.test_context,
+ IgniteThinJdbcConfiguration(
+ version=IgniteVersion(thin_jdbc_version),
+ addresses=[address]
+ ),
+
java_class_name="org.apache.ignite.internal.ducktest.tests.jdbc.JdbcThinSelfTestApplication",
+ num_nodes=1)
+
+ app.start()
+ app.stop()
+
+ ignite.stop()