This is an automated email from the ASF dual-hosted git repository.

lidavidm pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-adbc.git


The following commit(s) were added to refs/heads/main by this push:
     new ca17097  Add test suite for Java ADBC drivers (#31)
ca17097 is described below

commit ca17097b1e4a704fd8ba97e7c44ac2d99392374b
Author: David Li <[email protected]>
AuthorDate: Fri Jul 8 13:51:45 2022 -0400

    Add test suite for Java ADBC drivers (#31)
---
 .../org/apache/arrow/adbc/core/AdbcConnection.java |  25 ++++
 .../org/apache/arrow/adbc/core/AdbcStatement.java  |   7 -
 java/driver/jdbc-util/pom.xml                      |   5 +
 .../driver/jdbc/util/MockPreparedStatement.java    |   1 +
 java/driver/jdbc/pom.xml                           |   7 +-
 .../arrow/adbc/driver/jdbc/JdbcConnection.java     |  36 +++++
 .../arrow/adbc/driver/jdbc/JdbcStatement.java      |  25 ++--
 .../arrow/adbc/driver/jdbc/JdbcConnectionTest.java |  36 +++++
 .../arrow/adbc/driver/jdbc/JdbcDatabaseTest.java   | 107 --------------
 .../arrow/adbc/driver/jdbc/JdbcStatementTest.java  |  37 +++++
 .../adbc/driver/jdbc/JdbcTransactionTest.java      |  36 +++++
 java/driver/{jdbc-util => testsuite}/pom.xml       |  16 +-
 .../driver/testsuite/AbstractConnectionTest.java   |  49 ++++++
 .../driver/testsuite/AbstractStatementTest.java    |  99 +++++++++++++
 .../driver/testsuite/AbstractTransactionTest.java  | 164 +++++++++++++++++++++
 .../adbc/driver/testsuite/ArrowAssertions.java     |  55 +++++++
 java/pom.xml                                       |  11 ++
 17 files changed, 580 insertions(+), 136 deletions(-)

diff --git 
a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java 
b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java
index f6cb228..0917f65 100644
--- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java
+++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcConnection.java
@@ -16,6 +16,8 @@
  */
 package org.apache.arrow.adbc.core;
 
+import org.apache.arrow.vector.VectorSchemaRoot;
+
 /** A connection to a {@link AdbcDatabase}. */
 public interface AdbcConnection extends AutoCloseable {
   /**
@@ -32,6 +34,11 @@ public interface AdbcConnection extends AutoCloseable {
   /** Create a new statement that can be executed. */
   AdbcStatement createStatement() throws AdbcException;
 
+  /** Create a new statement to bulk insert a {@link VectorSchemaRoot} into a 
table. */
+  default AdbcStatement bulkIngest(String targetTableName) throws 
AdbcException {
+    throw new UnsupportedOperationException("Connection does not support bulk 
ingestion");
+  }
+
   /**
    * Rollback the pending transaction.
    *
@@ -42,4 +49,22 @@ public interface AdbcConnection extends AutoCloseable {
   default void rollback() throws AdbcException {
     throw new UnsupportedOperationException("Connection does not support 
transactions");
   }
+
+  /**
+   * Get the autocommit state.
+   *
+   * <p>Connections start in autocommit mode by default.
+   */
+  default boolean getAutoCommit() throws AdbcException {
+    return true;
+  }
+
+  /**
+   * Toggle whether autocommit is enabled.
+   *
+   * @throws UnsupportedOperationException if the database does not support 
toggling autocommit
+   */
+  default void setAutoCommit(boolean enableAutoCommit) throws AdbcException {
+    throw new UnsupportedOperationException("Connection does not support 
transactions");
+  }
 }
diff --git 
a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcStatement.java 
b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcStatement.java
index dbba624..6b464e9 100644
--- a/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcStatement.java
+++ b/java/core/src/main/java/org/apache/arrow/adbc/core/AdbcStatement.java
@@ -24,13 +24,6 @@ import org.apache.arrow.vector.VectorSchemaRoot;
 import org.apache.arrow.vector.ipc.ArrowReader;
 
 public interface AdbcStatement extends AutoCloseable {
-  /**
-   * The name of the target table for a bulk insert.
-   *
-   * @see #setOption(String, String)
-   */
-  String INGEST_OPTION_TARGET_TABLE = "adbc.ingest.target_table";
-
   /** Set a generic query option. */
   default void setOption(String key, String value) {
     throw new UnsupportedOperationException("Unsupported option " + key);
diff --git a/java/driver/jdbc-util/pom.xml b/java/driver/jdbc-util/pom.xml
index 8aa20f2..44b5405 100644
--- a/java/driver/jdbc-util/pom.xml
+++ b/java/driver/jdbc-util/pom.xml
@@ -49,5 +49,10 @@
       <artifactId>junit-jupiter</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.arrow.adbc</groupId>
+      <artifactId>adbc-driver-testsuite</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>
diff --git 
a/java/driver/jdbc-util/src/test/java/org/apache/arrow/adbc/driver/jdbc/util/MockPreparedStatement.java
 
b/java/driver/jdbc-util/src/test/java/org/apache/arrow/adbc/driver/jdbc/util/MockPreparedStatement.java
index bbaea4b..51ae7db 100644
--- 
a/java/driver/jdbc-util/src/test/java/org/apache/arrow/adbc/driver/jdbc/util/MockPreparedStatement.java
+++ 
b/java/driver/jdbc-util/src/test/java/org/apache/arrow/adbc/driver/jdbc/util/MockPreparedStatement.java
@@ -158,6 +158,7 @@ class MockPreparedStatement implements PreparedStatement {
   }
 
   @Override
+  @Deprecated
   public void setUnicodeStream(int parameterIndex, InputStream x, int length) 
throws SQLException {
     parameters.put(parameterIndex, new ParameterHolder(x, null));
   }
diff --git a/java/driver/jdbc/pom.xml b/java/driver/jdbc/pom.xml
index 1437f59..105ad4f 100644
--- a/java/driver/jdbc/pom.xml
+++ b/java/driver/jdbc/pom.xml
@@ -18,7 +18,7 @@
     <relativePath>../../pom.xml</relativePath>
   </parent>
 
-  <artifactId>adbc-driver-derby</artifactId>
+  <artifactId>adbc-driver-jdbc</artifactId>
   <packaging>jar</packaging>
   <name>Arrow ADBC Driver JDBC</name>
   <description>An ADBC driver wrapping the JDBC API.</description>
@@ -77,5 +77,10 @@
       <artifactId>junit-jupiter</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.arrow.adbc</groupId>
+      <artifactId>adbc-driver-testsuite</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>
diff --git 
a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcConnection.java
 
b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcConnection.java
index c2e4091..71554f9 100644
--- 
a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcConnection.java
+++ 
b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcConnection.java
@@ -35,6 +35,7 @@ public class JdbcConnection implements AdbcConnection {
   @Override
   public void commit() throws AdbcException {
     try {
+      checkAutoCommit();
       connection.commit();
     } catch (SQLException e) {
       throw JdbcDriverUtil.fromSqlException(e);
@@ -46,17 +47,52 @@ public class JdbcConnection implements AdbcConnection {
     return new JdbcStatement(allocator, connection);
   }
 
+  @Override
+  public AdbcStatement bulkIngest(String targetTableName) throws AdbcException 
{
+    return JdbcStatement.ingestRoot(allocator, connection, targetTableName);
+  }
+
   @Override
   public void rollback() throws AdbcException {
     try {
+      checkAutoCommit();
       connection.rollback();
     } catch (SQLException e) {
       throw JdbcDriverUtil.fromSqlException(e);
     }
   }
 
+  @Override
+  public boolean getAutoCommit() throws AdbcException {
+    try {
+      return connection.getAutoCommit();
+    } catch (SQLException e) {
+      throw JdbcDriverUtil.fromSqlException(e);
+    }
+  }
+
+  @Override
+  public void setAutoCommit(boolean enableAutoCommit) throws AdbcException {
+    try {
+      connection.setAutoCommit(enableAutoCommit);
+    } catch (SQLException e) {
+      throw JdbcDriverUtil.fromSqlException(e);
+    }
+  }
+
   @Override
   public void close() throws Exception {
     connection.close();
   }
+
+  private void checkAutoCommit() throws SQLException {
+    if (connection.getAutoCommit()) {
+      throw new IllegalStateException("Cannot perform operation in autocommit 
mode");
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "JdbcConnection{" + "connection=" + connection + '}';
+  }
 }
diff --git 
a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatement.java
 
b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatement.java
index d21fc80..56bb626 100644
--- 
a/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatement.java
+++ 
b/java/driver/jdbc/src/main/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatement.java
@@ -27,6 +27,7 @@ import org.apache.arrow.adbc.core.AdbcException;
 import org.apache.arrow.adbc.core.AdbcStatement;
 import org.apache.arrow.adbc.driver.jdbc.util.JdbcParameterBinder;
 import org.apache.arrow.memory.BufferAllocator;
+import org.apache.arrow.util.AutoCloseables;
 import org.apache.arrow.vector.VectorSchemaRoot;
 import org.apache.arrow.vector.ipc.ArrowReader;
 import org.apache.arrow.vector.types.pojo.Field;
@@ -36,6 +37,7 @@ public class JdbcStatement implements AdbcStatement {
   private final Connection connection;
 
   // State for SQL queries
+  private Statement statement;
   private String sqlQuery;
   private ResultSet resultSet;
   // State for bulk ingest
@@ -48,14 +50,12 @@ public class JdbcStatement implements AdbcStatement {
     this.sqlQuery = null;
   }
 
-  @Override
-  public void setOption(String key, String value) {
-    if (AdbcStatement.INGEST_OPTION_TARGET_TABLE.equals(key)) {
-      bulkTargetTable = Objects.requireNonNull(value);
-      sqlQuery = null;
-      return;
-    }
-    AdbcStatement.super.setOption(key, value);
+  static AdbcStatement ingestRoot(
+      BufferAllocator allocator, Connection connection, String 
targetTableName) {
+    Objects.requireNonNull(targetTableName);
+    final JdbcStatement statement = new JdbcStatement(allocator, connection);
+    statement.bulkTargetTable = targetTableName;
+    return statement;
   }
 
   @Override
@@ -109,7 +109,10 @@ public class JdbcStatement implements AdbcStatement {
           create.append(" INT");
           break;
         case FloatingPoint:
+          throw new UnsupportedOperationException("Type " + field);
         case Utf8:
+          create.append(" CLOB");
+          break;
         case LargeUtf8:
         case Binary:
         case LargeBinary:
@@ -164,7 +167,7 @@ public class JdbcStatement implements AdbcStatement {
       if (resultSet != null) {
         resultSet.close();
       }
-      final Statement statement =
+      statement =
           connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, 
ResultSet.CONCUR_READ_ONLY);
       resultSet = statement.executeQuery(sqlQuery);
     } catch (SQLException e) {
@@ -189,8 +192,6 @@ public class JdbcStatement implements AdbcStatement {
 
   @Override
   public void close() throws Exception {
-    if (resultSet != null) {
-      resultSet.close();
-    }
+    AutoCloseables.close(resultSet, statement);
   }
 }
diff --git 
a/java/driver/jdbc/src/test/java/org/apache/arrow/adbc/driver/jdbc/JdbcConnectionTest.java
 
b/java/driver/jdbc/src/test/java/org/apache/arrow/adbc/driver/jdbc/JdbcConnectionTest.java
new file mode 100644
index 0000000..bbfe424
--- /dev/null
+++ 
b/java/driver/jdbc/src/test/java/org/apache/arrow/adbc/driver/jdbc/JdbcConnectionTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.arrow.adbc.driver.jdbc;
+
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.arrow.adbc.core.AdbcDatabase;
+import org.apache.arrow.adbc.core.AdbcException;
+import org.apache.arrow.adbc.driver.testsuite.AbstractConnectionTest;
+import org.junit.jupiter.api.io.TempDir;
+
+public class JdbcConnectionTest extends AbstractConnectionTest {
+  @TempDir Path tempDir;
+
+  @Override
+  protected AdbcDatabase init() throws AdbcException {
+    final Map<String, String> parameters = new HashMap<>();
+    parameters.put("path", tempDir.toString() + "/db;create=true");
+    return JdbcDriver.INSTANCE.connect(parameters);
+  }
+}
diff --git 
a/java/driver/jdbc/src/test/java/org/apache/arrow/adbc/driver/jdbc/JdbcDatabaseTest.java
 
b/java/driver/jdbc/src/test/java/org/apache/arrow/adbc/driver/jdbc/JdbcDatabaseTest.java
deleted file mode 100644
index f80649f..0000000
--- 
a/java/driver/jdbc/src/test/java/org/apache/arrow/adbc/driver/jdbc/JdbcDatabaseTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * 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.arrow.adbc.driver.jdbc;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.nio.file.Path;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import org.apache.arrow.adbc.core.AdbcConnection;
-import org.apache.arrow.adbc.core.AdbcDatabase;
-import org.apache.arrow.adbc.core.AdbcStatement;
-import org.apache.arrow.memory.BufferAllocator;
-import org.apache.arrow.memory.RootAllocator;
-import org.apache.arrow.vector.FieldVector;
-import org.apache.arrow.vector.IntVector;
-import org.apache.arrow.vector.VectorSchemaRoot;
-import org.apache.arrow.vector.ipc.ArrowReader;
-import org.apache.arrow.vector.types.pojo.ArrowType;
-import org.apache.arrow.vector.types.pojo.Field;
-import org.apache.arrow.vector.types.pojo.Schema;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
-
-class JdbcDatabaseTest {
-  @BeforeAll
-  static void beforeAll() {
-    new org.apache.derby.jdbc.EmbeddedDriver();
-  }
-
-  @Test
-  void simpleQuery(@TempDir Path tempDir) throws Exception {
-    final Map<String, String> parameters = new HashMap<>();
-    parameters.put("path", tempDir.toString() + "/db;create=true");
-    try (final AdbcDatabase database = JdbcDriver.INSTANCE.connect(parameters);
-        final AdbcConnection connection = database.connect();
-        final AdbcStatement statement = connection.createStatement()) {
-      statement.setSqlQuery("SELECT * FROM SYS.SYSTABLES");
-      statement.execute();
-      try (final ArrowReader reader = statement.getArrowReader()) {
-        assertThat(reader.loadNextBatch()).isTrue();
-      }
-    }
-  }
-
-  @Test
-  void bulkInsert(@TempDir Path tempDir) throws Exception {
-    final Map<String, String> parameters = new HashMap<>();
-    parameters.put("path", tempDir.toString() + "/db;create=true");
-    final Schema schema =
-        new Schema(
-            Collections.singletonList(
-                Field.nullable("ints", new ArrowType.Int(32, /*signed=*/ 
true))));
-    try (final BufferAllocator allocator = new RootAllocator();
-        final AdbcDatabase database = JdbcDriver.INSTANCE.connect(parameters);
-        final AdbcConnection connection = database.connect()) {
-      try (final AdbcStatement statement = connection.createStatement();
-          final VectorSchemaRoot ingest = VectorSchemaRoot.create(schema, 
allocator)) {
-        statement.setOption(AdbcStatement.INGEST_OPTION_TARGET_TABLE, "foo");
-        statement.bind(ingest);
-        final IntVector ints = (IntVector) ingest.getVector(0);
-        ints.allocateNew(4);
-        ints.setSafe(0, 0);
-        ints.setSafe(1, 1);
-        ints.setSafe(2, 2);
-        ints.setSafe(3, 3);
-        ingest.setRowCount(4);
-        statement.execute();
-      }
-
-      try (final AdbcStatement statement = connection.createStatement()) {
-        statement.setSqlQuery("SELECT * FROM foo");
-        statement.execute();
-
-        try (final ArrowReader reader = statement.getArrowReader()) {
-          assertThat(reader.loadNextBatch()).isTrue();
-          final FieldVector vector = reader.getVectorSchemaRoot().getVector(0);
-          assertThat(vector).isInstanceOf(IntVector.class);
-          assertThat(vector.getValueCount()).isEqualTo(4);
-          final IntVector ints = (IntVector) vector;
-          for (int i = 0; i < 4; i++) {
-            assertThat(ints.isNull(i)).isFalse();
-            assertThat(ints.get(i)).isEqualTo(i);
-          }
-          assertThat(reader.loadNextBatch()).isFalse();
-        }
-      }
-    }
-  }
-}
diff --git 
a/java/driver/jdbc/src/test/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatementTest.java
 
b/java/driver/jdbc/src/test/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatementTest.java
new file mode 100644
index 0000000..d81347d
--- /dev/null
+++ 
b/java/driver/jdbc/src/test/java/org/apache/arrow/adbc/driver/jdbc/JdbcStatementTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.arrow.adbc.driver.jdbc;
+
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.arrow.adbc.core.AdbcDatabase;
+import org.apache.arrow.adbc.core.AdbcException;
+import org.apache.arrow.adbc.driver.testsuite.AbstractStatementTest;
+import org.junit.jupiter.api.io.TempDir;
+
+class JdbcStatementTest extends AbstractStatementTest {
+  @TempDir Path tempDir;
+
+  @Override
+  protected AdbcDatabase init() throws AdbcException {
+    final Map<String, String> parameters = new HashMap<>();
+    parameters.put("path", tempDir.toString() + "/db;create=true");
+    return JdbcDriver.INSTANCE.connect(parameters);
+  }
+}
diff --git 
a/java/driver/jdbc/src/test/java/org/apache/arrow/adbc/driver/jdbc/JdbcTransactionTest.java
 
b/java/driver/jdbc/src/test/java/org/apache/arrow/adbc/driver/jdbc/JdbcTransactionTest.java
new file mode 100644
index 0000000..622f5e8
--- /dev/null
+++ 
b/java/driver/jdbc/src/test/java/org/apache/arrow/adbc/driver/jdbc/JdbcTransactionTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.arrow.adbc.driver.jdbc;
+
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.arrow.adbc.core.AdbcDatabase;
+import org.apache.arrow.adbc.core.AdbcException;
+import org.apache.arrow.adbc.driver.testsuite.AbstractTransactionTest;
+import org.junit.jupiter.api.io.TempDir;
+
+public class JdbcTransactionTest extends AbstractTransactionTest {
+  @TempDir Path tempDir;
+
+  @Override
+  protected AdbcDatabase init() throws AdbcException {
+    final Map<String, String> parameters = new HashMap<>();
+    parameters.put("path", tempDir.toString() + "/db;create=true");
+    return JdbcDriver.INSTANCE.connect(parameters);
+  }
+}
diff --git a/java/driver/jdbc-util/pom.xml b/java/driver/testsuite/pom.xml
similarity index 84%
copy from java/driver/jdbc-util/pom.xml
copy to java/driver/testsuite/pom.xml
index 8aa20f2..cf489bc 100644
--- a/java/driver/jdbc-util/pom.xml
+++ b/java/driver/testsuite/pom.xml
@@ -15,20 +15,20 @@
     <artifactId>arrow-adbc-java-root</artifactId>
     <groupId>org.apache.arrow.adbc</groupId>
     <version>9.0.0-SNAPSHOT</version>
-    <relativePath>../../pom.xml</relativePath>
   </parent>
 
-  <artifactId>adbc-driver-jdbc-util</artifactId>
+  <artifactId>adbc-driver-testsuite</artifactId>
   <packaging>jar</packaging>
-  <name>Arrow ADBC Driver JDBC Util</name>
-  <description>Utilities for working with Arrow and JDBC.</description>
+  <name>Arrow ADBC Driver Test Suite</name>
+  <description>A reusable ADBC driver compliance/test suite.</description>
 
   <dependencies>
-    <!-- Arrow -->
     <dependency>
-      <groupId>org.apache.arrow</groupId>
-      <artifactId>arrow-jdbc</artifactId>
+      <groupId>org.apache.arrow.adbc</groupId>
+      <artifactId>adbc-core</artifactId>
     </dependency>
+
+    <!-- Arrow -->
     <dependency>
       <groupId>org.apache.arrow</groupId>
       <artifactId>arrow-memory-core</artifactId>
@@ -42,12 +42,10 @@
     <dependency>
       <groupId>org.assertj</groupId>
       <artifactId>assertj-core</artifactId>
-      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.junit.jupiter</groupId>
       <artifactId>junit-jupiter</artifactId>
-      <scope>test</scope>
     </dependency>
   </dependencies>
 </project>
diff --git 
a/java/driver/testsuite/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractConnectionTest.java
 
b/java/driver/testsuite/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractConnectionTest.java
new file mode 100644
index 0000000..fb22e8a
--- /dev/null
+++ 
b/java/driver/testsuite/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractConnectionTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.arrow.adbc.driver.testsuite;
+
+import org.apache.arrow.adbc.core.AdbcConnection;
+import org.apache.arrow.adbc.core.AdbcDatabase;
+import org.apache.arrow.adbc.core.AdbcException;
+import org.apache.arrow.util.AutoCloseables;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public abstract class AbstractConnectionTest {
+  protected AdbcDatabase database;
+  protected AdbcConnection connection;
+
+  protected abstract AdbcDatabase init() throws AdbcException;
+
+  @BeforeEach
+  public void beforeEach() throws Exception {
+    database = init();
+    connection = database.connect();
+  }
+
+  @AfterEach
+  public void afterEach() throws Exception {
+    AutoCloseables.close(connection, database);
+  }
+
+  @Test
+  void multipleConnections() throws Exception {
+    try (final AdbcConnection ignored = database.connect()) {}
+  }
+}
diff --git 
a/java/driver/testsuite/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractStatementTest.java
 
b/java/driver/testsuite/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractStatementTest.java
new file mode 100644
index 0000000..fc10c56
--- /dev/null
+++ 
b/java/driver/testsuite/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractStatementTest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.arrow.adbc.driver.testsuite;
+
+import static 
org.apache.arrow.adbc.driver.testsuite.ArrowAssertions.assertRoot;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import org.apache.arrow.adbc.core.AdbcConnection;
+import org.apache.arrow.adbc.core.AdbcDatabase;
+import org.apache.arrow.adbc.core.AdbcException;
+import org.apache.arrow.adbc.core.AdbcStatement;
+import org.apache.arrow.memory.BufferAllocator;
+import org.apache.arrow.memory.RootAllocator;
+import org.apache.arrow.util.AutoCloseables;
+import org.apache.arrow.vector.IntVector;
+import org.apache.arrow.vector.VarCharVector;
+import org.apache.arrow.vector.VectorSchemaRoot;
+import org.apache.arrow.vector.ipc.ArrowReader;
+import org.apache.arrow.vector.types.pojo.ArrowType;
+import org.apache.arrow.vector.types.pojo.Field;
+import org.apache.arrow.vector.types.pojo.Schema;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public abstract class AbstractStatementTest {
+  protected AdbcDatabase database;
+  protected AdbcConnection connection;
+  protected BufferAllocator allocator;
+
+  protected abstract AdbcDatabase init() throws AdbcException;
+
+  @BeforeEach
+  public void beforeEach() throws Exception {
+    database = init();
+    connection = database.connect();
+    allocator = new RootAllocator();
+  }
+
+  @AfterEach
+  public void afterEach() throws Exception {
+    AutoCloseables.close(connection, database, allocator);
+  }
+
+  @Test
+  public void bulkInsert() throws Exception {
+    final Schema schema =
+        new Schema(
+            Arrays.asList(
+                Field.nullable("INTS", new ArrowType.Int(32, /*signed=*/ 
true)),
+                Field.nullable("STRS", new ArrowType.Utf8())));
+    try (final VectorSchemaRoot root = VectorSchemaRoot.create(schema, 
allocator)) {
+      final IntVector ints = (IntVector) root.getVector(0);
+      final VarCharVector strs = (VarCharVector) root.getVector(1);
+
+      ints.allocateNew(4);
+      ints.setSafe(0, 0);
+      ints.setSafe(1, 1);
+      ints.setSafe(2, 2);
+      ints.setNull(3);
+      strs.allocateNew(4);
+      strs.setNull(0);
+      strs.setSafe(1, "foo".getBytes(StandardCharsets.UTF_8));
+      strs.setSafe(2, "".getBytes(StandardCharsets.UTF_8));
+      strs.setSafe(3, "asdf".getBytes(StandardCharsets.UTF_8));
+      root.setRowCount(4);
+
+      try (final AdbcStatement stmt = connection.bulkIngest("foo")) {
+        stmt.bind(root);
+        stmt.execute();
+      }
+      try (final AdbcStatement stmt = connection.createStatement()) {
+        stmt.setSqlQuery("SELECT * FROM foo");
+        stmt.execute();
+        try (ArrowReader arrowReader = stmt.getArrowReader()) {
+          assertThat(arrowReader.loadNextBatch()).isTrue();
+          assertRoot(arrowReader.getVectorSchemaRoot()).isEqualTo(root);
+        }
+      }
+    }
+  }
+}
diff --git 
a/java/driver/testsuite/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractTransactionTest.java
 
b/java/driver/testsuite/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractTransactionTest.java
new file mode 100644
index 0000000..96f0247
--- /dev/null
+++ 
b/java/driver/testsuite/src/main/java/org/apache/arrow/adbc/driver/testsuite/AbstractTransactionTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.arrow.adbc.driver.testsuite;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.Collections;
+import org.apache.arrow.adbc.core.AdbcConnection;
+import org.apache.arrow.adbc.core.AdbcDatabase;
+import org.apache.arrow.adbc.core.AdbcException;
+import org.apache.arrow.adbc.core.AdbcStatement;
+import org.apache.arrow.memory.BufferAllocator;
+import org.apache.arrow.memory.RootAllocator;
+import org.apache.arrow.util.AutoCloseables;
+import org.apache.arrow.vector.IntVector;
+import org.apache.arrow.vector.VectorSchemaRoot;
+import org.apache.arrow.vector.types.pojo.ArrowType;
+import org.apache.arrow.vector.types.pojo.Field;
+import org.apache.arrow.vector.types.pojo.Schema;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public abstract class AbstractTransactionTest {
+  protected BufferAllocator allocator;
+  protected AdbcDatabase database;
+  protected AdbcConnection connection;
+
+  protected abstract AdbcDatabase init() throws AdbcException;
+
+  @BeforeEach
+  public void beforeEach() throws Exception {
+    database = init();
+    connection = database.connect();
+    allocator = new RootAllocator();
+  }
+
+  @AfterEach
+  public void afterEach() throws Exception {
+    AutoCloseables.close(connection, database, allocator);
+  }
+
+  @Test
+  void autoCommitByDefault() throws Exception {
+    assertThrows(IllegalStateException.class, () -> connection.commit());
+    assertThrows(IllegalStateException.class, () -> connection.rollback());
+    assertThat(connection.getAutoCommit()).isTrue();
+  }
+
+  @Test
+  void toggleAutoCommit() throws Exception {
+    assertThat(connection.getAutoCommit()).isTrue();
+    connection.setAutoCommit(true);
+    assertThat(connection.getAutoCommit()).isTrue();
+    connection.setAutoCommit(false);
+    assertThat(connection.getAutoCommit()).isFalse();
+    connection.setAutoCommit(true);
+    assertThat(connection.getAutoCommit()).isTrue();
+  }
+
+  @Test
+  void rollback() throws Exception {
+    final Schema schema =
+        new Schema(
+            Collections.singletonList(
+                Field.nullable("ints", new ArrowType.Int(32, /*signed=*/ 
true))));
+
+    connection.setAutoCommit(false);
+    try (VectorSchemaRoot root = VectorSchemaRoot.create(schema, allocator)) {
+      final IntVector ints = (IntVector) root.getVector(0);
+      ints.setSafe(0, 1);
+      ints.setSafe(1, 2);
+      root.setRowCount(2);
+      try (final AdbcStatement stmt = connection.bulkIngest("foo")) {
+        stmt.bind(root);
+        stmt.execute();
+      }
+      try (final AdbcStatement stmt = connection.createStatement()) {
+        stmt.setSqlQuery("SELECT * FROM foo");
+        stmt.execute();
+      }
+      connection.rollback();
+      try (final AdbcStatement stmt = connection.createStatement()) {
+        stmt.setSqlQuery("SELECT * FROM foo");
+        assertThrows(AdbcException.class, stmt::execute);
+      }
+    }
+  }
+
+  @Test
+  void commit() throws Exception {
+    final Schema schema =
+        new Schema(
+            Collections.singletonList(
+                Field.nullable("ints", new ArrowType.Int(32, /*signed=*/ 
true))));
+
+    connection.setAutoCommit(false);
+    try (VectorSchemaRoot root = VectorSchemaRoot.create(schema, allocator)) {
+      final IntVector ints = (IntVector) root.getVector(0);
+      ints.setSafe(0, 1);
+      ints.setSafe(1, 2);
+      root.setRowCount(2);
+      try (final AdbcStatement stmt = connection.bulkIngest("foo")) {
+        stmt.bind(root);
+        stmt.execute();
+      }
+      try (final AdbcStatement stmt = connection.createStatement()) {
+        stmt.setSqlQuery("SELECT * FROM foo");
+        stmt.execute();
+      }
+      connection.commit();
+      try (final AdbcStatement stmt = connection.createStatement()) {
+        stmt.setSqlQuery("SELECT * FROM foo");
+        stmt.execute();
+      }
+      connection.commit();
+    }
+  }
+
+  @Test
+  void enableAutoCommitAlsoCommits() throws Exception {
+    final Schema schema =
+        new Schema(
+            Collections.singletonList(
+                Field.nullable("ints", new ArrowType.Int(32, /*signed=*/ 
true))));
+
+    connection.setAutoCommit(false);
+    try (VectorSchemaRoot root = VectorSchemaRoot.create(schema, allocator)) {
+      final IntVector ints = (IntVector) root.getVector(0);
+      ints.setSafe(0, 1);
+      ints.setSafe(1, 2);
+      root.setRowCount(2);
+      try (final AdbcStatement stmt = connection.bulkIngest("foo")) {
+        stmt.bind(root);
+        stmt.execute();
+      }
+      try (final AdbcStatement stmt = connection.createStatement()) {
+        stmt.setSqlQuery("SELECT * FROM foo");
+        stmt.execute();
+      }
+      connection.setAutoCommit(true);
+      try (final AdbcStatement stmt = connection.createStatement()) {
+        stmt.setSqlQuery("SELECT * FROM foo");
+        stmt.execute();
+      }
+    }
+  }
+}
diff --git 
a/java/driver/testsuite/src/main/java/org/apache/arrow/adbc/driver/testsuite/ArrowAssertions.java
 
b/java/driver/testsuite/src/main/java/org/apache/arrow/adbc/driver/testsuite/ArrowAssertions.java
new file mode 100644
index 0000000..194fa00
--- /dev/null
+++ 
b/java/driver/testsuite/src/main/java/org/apache/arrow/adbc/driver/testsuite/ArrowAssertions.java
@@ -0,0 +1,55 @@
+/*
+ * 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.arrow.adbc.driver.testsuite;
+
+import org.apache.arrow.vector.VectorSchemaRoot;
+import org.assertj.core.api.AbstractAssert;
+
+/** AssertJ assertions for Arrow. */
+public final class ArrowAssertions {
+  /** Assert on a {@link VectorSchemaRoot}. */
+  public static VectorSchemaRootAssert assertRoot(VectorSchemaRoot actual) {
+    return new VectorSchemaRootAssert(actual);
+  }
+
+  public static final class VectorSchemaRootAssert
+      extends AbstractAssert<VectorSchemaRootAssert, VectorSchemaRoot> {
+    VectorSchemaRootAssert(VectorSchemaRoot vectorSchemaRoot) {
+      super(vectorSchemaRoot, VectorSchemaRootAssert.class);
+    }
+
+    @Override
+    public VectorSchemaRootAssert isEqualTo(Object expected) {
+      if (!(expected instanceof VectorSchemaRoot)) {
+        throw failure(
+            "Expected object is not a VectorSchemaRoot, but rather a %s",
+            expected.getClass().getName());
+      }
+      final VectorSchemaRoot expectedRoot = (VectorSchemaRoot) expected;
+      if (!actual.equals(expectedRoot)) {
+        throw failureWithActualExpected(
+            actual,
+            expected,
+            "Expected Root:\n%sActual Root:\n%s",
+            expectedRoot.contentToTSVString(),
+            actual.contentToTSVString());
+      }
+      return this;
+    }
+  }
+}
diff --git a/java/pom.xml b/java/pom.xml
index 8645c11..8dc6657 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -70,6 +70,7 @@
     <module>core</module>
     <module>driver/jdbc</module>
     <module>driver/jdbc-util</module>
+    <module>driver/testsuite</module>
     <module>driver-manager</module>
   </modules>
 
@@ -97,11 +98,21 @@
         <artifactId>adbc-core</artifactId>
         <version>${adbc.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.arrow.adbc</groupId>
+        <artifactId>adbc-driver-jdbc</artifactId>
+        <version>${adbc.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.arrow.adbc</groupId>
         <artifactId>adbc-driver-jdbc-util</artifactId>
         <version>${adbc.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.arrow.adbc</groupId>
+        <artifactId>adbc-driver-testsuite</artifactId>
+        <version>${adbc.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.arrow.adbc</groupId>
         <artifactId>adbc-driver-manager</artifactId>

Reply via email to