diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 305904872c..40c256014f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -209,6 +209,10 @@ jobs:
working-directory: integration_tests/sdk/go
run: |
go run main.go
+ - name: Run Java SDK tests
+ working-directory: integration_tests
+ run: |
+ make run-java
- name: Upload Logs
if: always()
uses: actions/upload-artifact@v3
diff --git a/integration_tests/Makefile b/integration_tests/Makefile
index 4a50bccbc6..aa4d4baedf 100644
--- a/integration_tests/Makefile
+++ b/integration_tests/Makefile
@@ -44,3 +44,7 @@ kill-old-process:
run: clean build kill-old-process
RUST_BACKTRACE=1 $(CERESDB_TEST_BINARY)
+
+run-java:
+ java -version
+ cd sdk/java && MAVEN_OPTS="--add-opens=java.base/java.nio=ALL-UNNAMED" mvn clean compile exec:java
diff --git a/integration_tests/sdk/java/pom.xml b/integration_tests/sdk/java/pom.xml
new file mode 100644
index 0000000000..d4f53e166e
--- /dev/null
+++ b/integration_tests/sdk/java/pom.xml
@@ -0,0 +1,72 @@
+
+
+
+ 4.0.0
+
+ io.ceresdb
+ tests
+ 1.0-SNAPSHOT
+
+ ceresdb-integration-test
+ https://github.com/CeresDB/ceresdb/
+
+
+ UTF-8
+ 1.8
+ 1.8
+ 2.8.2
+ 1.0.1
+
+
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-api
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-slf4j-impl
+ ${log4j.version}
+
+
+
+ io.ceresdb
+ ceresdb-all
+ ${ceresdb.version}
+
+
+ junit
+ junit
+ 4.12
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.6.0
+
+
+
+ java
+
+
+
+
+ io.ceresdb.App
+
+
+
+
+
+
diff --git a/integration_tests/sdk/java/src/main/java/io/ceresdb/App.java b/integration_tests/sdk/java/src/main/java/io/ceresdb/App.java
new file mode 100644
index 0000000000..feff33732b
--- /dev/null
+++ b/integration_tests/sdk/java/src/main/java/io/ceresdb/App.java
@@ -0,0 +1,103 @@
+package io.ceresdb;
+
+import io.ceresdb.models.*;
+import io.ceresdb.options.CeresDBOptions;
+import org.junit.Assert;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import static io.ceresdb.RouteMode.DIRECT;
+
+public class App {
+ private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
+
+ private static String TABLE = "table_for_java_tests" + System.currentTimeMillis();
+ private static String HOST = "localhost";
+ private static int PORT = 8831;
+ private static CeresDBClient CLIENT;
+
+ static {
+ final CeresDBOptions opts = CeresDBOptions.newBuilder(HOST, PORT, DIRECT) // CeresDB default grpc port 8831,use DIRECT RouteMode
+ .database("public") // use database for client, can be overridden by the RequestContext in request
+ // maximum retry times when write fails
+ // (only some error codes will be retried, such as the routing table failure)
+ .writeMaxRetries(1)
+ // maximum retry times when read fails
+ // (only some error codes will be retried, such as the routing table failure)
+ .readMaxRetries(1).build();
+
+ CLIENT = new CeresDBClient();
+ if (!CLIENT.init(opts)) {
+ throw new IllegalStateException("Fail to start CeresDBClient");
+ }
+ }
+
+ private static void query(long now, boolean addNewColumn) throws Throwable {
+ final SqlQueryRequest queryRequest = SqlQueryRequest.newBuilder()
+ .forTables(TABLE) // table name is optional. If not provided, SQL parser will parse the `ssql` to get the table name and do the routing automaticly
+ .sql("select * from %s where timestamp = %d", TABLE, now)
+ .build();
+ final CompletableFuture> qf = CLIENT.sqlQuery(queryRequest);
+ final Result queryResult = qf.get();
+
+ Assert.assertTrue(queryResult.isOk());
+
+ final SqlQueryOk queryOk = queryResult.getOk();
+ // TODO: add row equal assert
+ LOGGER.warn("result {}", queryOk.getRowList());
+ Assert.assertEquals(2, queryOk.getRowCount());
+ }
+
+ private static void write(long now, boolean addNewColumn) throws Throwable {
+ List points = new LinkedList<>();
+ for (int i = 0; i < 2; i++) {
+ Point.PointBuilder pointBuilder = Point.newPointBuilder(TABLE)
+ .setTimestamp(now)
+ .addTag("tag", String.format("tag-%d", i))
+ .addField("value", Value.withInt8(10 + i));
+ if (addNewColumn) {
+ pointBuilder = pointBuilder
+ .addTag("new-tag", String.format("new-tag-%d", i));
+ }
+
+ points.add(pointBuilder.build());
+ }
+ final CompletableFuture> wf = CLIENT.write(new WriteRequest(points));
+ final Result writeResult = wf.get();
+ Assert.assertTrue(writeResult.isOk());
+ }
+
+ private static void checkAutoCreateTable() throws Throwable {
+ long now = System.currentTimeMillis();
+ write(now, false);
+ query(now, false);
+ }
+
+ private static void checkAutoAddColumns() throws Throwable {
+ long now = System.currentTimeMillis();
+ write(now, true);
+ query(now, true);
+ }
+
+ private static void run() throws Throwable {
+ checkAutoCreateTable();
+ checkAutoAddColumns();
+ }
+
+ public static void main(String[] args) {
+ LOGGER.warn("Begin tests, table:{}", TABLE);
+ try {
+ run();
+ } catch (Throwable e) {
+ LOGGER.error("Test failed", e);
+ System.exit(1);
+ }
+
+ LOGGER.warn("Test finish.");
+ System.exit(0);
+ }
+}
diff --git a/integration_tests/sdk/java/src/main/resources/log4j2.xml b/integration_tests/sdk/java/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000..7e09071b77
--- /dev/null
+++ b/integration_tests/sdk/java/src/main/resources/log4j2.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file