diff --git a/src/main/java/io/github/mapapire/Pool.java b/src/main/java/io/github/mapapire/Pool.java index 26987cb..cc3ba47 100644 --- a/src/main/java/io/github/mapapire/Pool.java +++ b/src/main/java/io/github/mapapire/Pool.java @@ -29,6 +29,7 @@ class PoolOptions { PoolOptions(DaemonServer creds, int maxSize, int startingSize) { this.creds = creds; + this.opts = new JDBCOptions(); this.maxSize = maxSize; this.startingSize = startingSize; } @@ -235,24 +236,22 @@ public CompletableFuture popJob() { } } - // TODO: Fix optional parm public Query query(String sql) { - return this.query(sql, null); + QueryOptions options = new QueryOptions(); + return this.query(sql, options); } - // TODO: Fix optional parm public Query query(String sql, QueryOptions opts) { SqlJob job = this.getJob(); return job.query(sql, opts); } - // TODO: Fix optional parm - public CompletableFuture> execute(String sql) { - return this.execute(sql, null); + public CompletableFuture> execute(String sql) throws Exception { + QueryOptions options = new QueryOptions(); + return this.execute(sql, options); } - // TODO: Fix optional parm - public CompletableFuture> execute(String sql, QueryOptions opts) { + public CompletableFuture> execute(String sql, QueryOptions opts) throws Exception { SqlJob job = this.getJob(); return job.execute(sql, opts); } diff --git a/src/main/java/io/github/mapapire/Query.java b/src/main/java/io/github/mapapire/Query.java index 42f53dc..d70bb99 100644 --- a/src/main/java/io/github/mapapire/Query.java +++ b/src/main/java/io/github/mapapire/Query.java @@ -85,16 +85,16 @@ public void cleanup() { .collect(Collectors.toList()); } - public CompletableFuture> execute() { + public CompletableFuture> execute() throws Exception { return this.execute(100); } - public CompletableFuture> execute(int rowsToFetch) { + public CompletableFuture> execute(int rowsToFetch) throws Exception { switch (this.state) { case RUN_MORE_DATA_AVAILABLE: - throw new Error("Statement has already been run"); + throw new Exception("Statement has already been run"); case RUN_DONE: - throw new Error("Statement has already been fully run"); + throw new Exception("Statement has already been fully run"); } ObjectNode queryObject = objectMapper.createObjectNode(); @@ -158,23 +158,23 @@ public CompletableFuture> execute(int rowsToFetch) { errorList.add("Failed to run query (unknown error)"); } - throw new Error(String.join(", ", errorList)); + throw new Exception(String.join(", ", errorList)); } this.correlationId = queryResult.getId(); return CompletableFuture.completedFuture(queryResult); } - public CompletableFuture> fetchMore() { + public CompletableFuture> fetchMore() throws Exception { return this.fetchMore(this.rowsToFetch); } - public CompletableFuture> fetchMore(int rowsToFetch) { + public CompletableFuture> fetchMore(int rowsToFetch) throws Exception { switch (this.state) { case NOT_YET_RUN: - throw new Error("Statement has not yet been run"); + throw new Exception("Statement has not yet been run"); case RUN_DONE: - throw new Error("Statement has already been fully run"); + throw new Exception("Statement has already been fully run"); } ObjectNode queryObject = objectMapper.createObjectNode(); @@ -202,9 +202,9 @@ public CompletableFuture> fetchMore(int rowsToFetch) { String error = queryResult.getError(); if (error != null) { - throw new Error(error.toString()); + throw new Exception(error.toString()); } else { - throw new Error("Failed to run query (unknown error)"); + throw new Exception("Failed to run query (unknown error)"); } } diff --git a/src/main/java/io/github/mapapire/SqlJob.java b/src/main/java/io/github/mapapire/SqlJob.java index 9f6c57c..81d603c 100644 --- a/src/main/java/io/github/mapapire/SqlJob.java +++ b/src/main/java/io/github/mapapire/SqlJob.java @@ -212,7 +212,7 @@ public int getRunningCount() { } // TODO: - public CompletableFuture connect(DaemonServer db2Server) { + public CompletableFuture connect(DaemonServer db2Server) throws Exception { this.status = JobStatus.Connecting; try { this.socket = this.getChannel(db2Server).get(); @@ -267,9 +267,9 @@ public CompletableFuture connect(DaemonServer db2Server) { this.dispose(); this.status = JobStatus.NotStarted; if (connectResult.getError() != null) { - throw new Error(connectResult.getError()); + throw new Exception(connectResult.getError()); } else { - throw new Error("Failed to connect to server."); + throw new Exception("Failed to connect to server."); } } @@ -288,12 +288,12 @@ public Query query(String sql, QueryOptions opts) { return new Query(this, sql, opts); } - public CompletableFuture> execute(String sql) { + public CompletableFuture> execute(String sql) throws Exception { QueryOptions options = new QueryOptions(); return this.execute(sql, options); } - public CompletableFuture> execute(String sql, QueryOptions opts) { + public CompletableFuture> execute(String sql, QueryOptions opts) throws Exception { Query query = query(sql, opts); CompletableFuture> future = query.execute(); try { @@ -301,7 +301,7 @@ public CompletableFuture> execute(String sql, QueryOptions op query.close().get(); if (result.getError() != null) { - throw new Error(result.getError()); + throw new Exception(result.getError()); } return CompletableFuture.completedFuture(result); @@ -311,7 +311,7 @@ public CompletableFuture> execute(String sql, QueryOptions op } } - public CompletableFuture getVersion() { + public CompletableFuture getVersion() throws Exception { ObjectNode verObj = objectMapper.createObjectNode(); verObj.put("id", SqlJob.getNewUniqueId()); verObj.put("type", "getversion"); @@ -334,20 +334,20 @@ public CompletableFuture getVersion() { if (!version.getSuccess()) { if (version.getError() != null) { - throw new Error(version.getError()); + throw new Exception(version.getError()); } else { - throw new Error("Failed to get version from backend"); + throw new Exception("Failed to get version from backend"); } } return CompletableFuture.completedFuture(version); } - public CompletableFuture> explain(String statement) { + public CompletableFuture> explain(String statement) throws Exception { return this.explain(statement, ExplainType.Run); } - public CompletableFuture> explain(String statement, ExplainType type) { + public CompletableFuture> explain(String statement, ExplainType type) throws Exception { ObjectNode explainRequest = objectMapper.createObjectNode(); explainRequest.put("id", SqlJob.getNewUniqueId()); explainRequest.put("type", "dove"); @@ -372,9 +372,9 @@ public CompletableFuture> explain(String statement, ExplainTyp if (!explainResult.getSuccess()) { if (explainResult.getError() != null) { - throw new Error(explainResult.getError()); + throw new Exception(explainResult.getError()); } else { - throw new Error("Failed to explain."); + throw new Exception("Failed to explain."); } } @@ -385,7 +385,7 @@ public String getTraceFilePath() { return this.traceFile; } - public CompletableFuture getTraceData() { + public CompletableFuture getTraceData() throws Exception { ObjectNode tracedataReqObj = objectMapper.createObjectNode(); tracedataReqObj.put("id", SqlJob.getNewUniqueId()); tracedataReqObj.put("type", "gettracedata"); @@ -408,16 +408,16 @@ public CompletableFuture getTraceData() { if (!rpy.getSuccess()) { if (rpy.getError() != null) { - throw new Error(rpy.getError()); + throw new Exception(rpy.getError()); } else { - throw new Error("Failed to get trace data from backend"); + throw new Exception("Failed to get trace data from backend"); } } return CompletableFuture.completedFuture(rpy); } - public CompletableFuture setTraceConfig(ServerTraceDest dest, ServerTraceLevel level) { + public CompletableFuture setTraceConfig(ServerTraceDest dest, ServerTraceLevel level) throws Exception { ObjectNode reqObj = objectMapper.createObjectNode(); reqObj.put("id", SqlJob.getNewUniqueId()); reqObj.put("type", "setconfig"); @@ -444,9 +444,9 @@ public CompletableFuture setTraceConfig(ServerTraceDest dest, S if (!rpy.getSuccess()) { if (rpy.getError() != null) { - throw new Error(rpy.getError()); + throw new Exception(rpy.getError()); } else { - throw new Error("Failed to set trace options on backend"); + throw new Exception("Failed to set trace options on backend"); } } @@ -487,7 +487,7 @@ public boolean underCommitControl() { // }); // } - public CompletableFuture> endTransaction(TransactionEndType type) { + public CompletableFuture> endTransaction(TransactionEndType type) throws Exception { String query; switch (type) { diff --git a/src/test/java/io/github/mapapire/MapepireTest.java b/src/test/java/io/github/mapapire/MapepireTest.java new file mode 100644 index 0000000..047840a --- /dev/null +++ b/src/test/java/io/github/mapapire/MapepireTest.java @@ -0,0 +1,51 @@ +package io.github.mapapire; + +import io.github.mapapire.types.DaemonServer; + +import java.io.InputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.junit.jupiter.api.BeforeAll; + +import com.fasterxml.jackson.databind.ObjectMapper; + +class MapepireTest { + private static final String CONFIG_FILE = "config.properties"; + public static DaemonServer creds; + public static final ObjectMapper objectMapper = new ObjectMapper(); + + @BeforeAll + public static void setup() throws Exception { + Properties properties = new Properties(); + try (InputStream input = MapepireTest.class.getClassLoader().getResourceAsStream(CONFIG_FILE)) { + if (input == null) { + throw new IOException("Unable to find " + CONFIG_FILE); + } + properties.load(input); + } + + List keys = Arrays.asList("IBMI_HOST", "IBMI_USER", "IBMI_PASSWORD", "IBMI_PORT"); + Map secrets = new HashMap<>(); + for (String key : keys) { + String value = properties.getProperty(key); + if (value.equals("")) { + throw new Exception(key + " not set in config.properties"); + } + secrets.put(key, value); + } + + String host = secrets.get(keys.get(0)); + String user = secrets.get(keys.get(1)); + String password = secrets.get(keys.get(2)); + int port = Integer.parseInt(secrets.get(keys.get(3))); + + creds = new DaemonServer(host, port, user, password, true, ""); + + // TODO: Get certificate + } +} diff --git a/src/test/java/io/github/mapapire/PoolTest.java b/src/test/java/io/github/mapapire/PoolTest.java new file mode 100644 index 0000000..420064a --- /dev/null +++ b/src/test/java/io/github/mapapire/PoolTest.java @@ -0,0 +1,56 @@ +package io.github.mapapire; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import org.junit.jupiter.api.Test; + +import io.github.mapapire.types.QueryResult; + +class PoolTest extends MapepireTest { + @Test + @SuppressWarnings("unchecked") + void simplePoolUsingPoolExecute() throws Exception { + PoolOptions options = new PoolOptions(MapepireTest.creds, 5, 3); + Pool pool = new Pool(options); + pool.init().get(); + + List>> futuresA = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + futuresA.add(pool.execute("values (job_name)")); + } + CompletableFuture allOfA = CompletableFuture.allOf(futuresA.toArray(new CompletableFuture[0])); + allOfA.join(); + + List jobNamesA = new ArrayList<>(); + for (CompletableFuture> future : futuresA) { + jobNamesA.add(((HashMap) future.get().getData().get(0)).get("00001")); + } + + assertEquals(3, jobNamesA.size()); + assertEquals(3, pool.getActiveJobCount()); + + List>> futuresB = new ArrayList<>(); + for (int i = 0; i < 15; i++) { + futuresB.add(pool.execute("values (job_name)")); + } + CompletableFuture allOfB = CompletableFuture.allOf(futuresB.toArray(new CompletableFuture[0])); + allOfB.join(); + + List jobNamesB = new ArrayList<>(); + for (CompletableFuture> future : futuresB) { + jobNamesB.add(((HashMap) future.get().getData().get(0)).get("00001")); + } + + assertEquals(15, jobNamesB.size()); + assertTrue(pool.getActiveJobCount() >= 3); + assertTrue(pool.getActiveJobCount() <= 5); + + pool.end(); + } +} diff --git a/src/test/java/io/github/mapapire/SimpleTest.java b/src/test/java/io/github/mapapire/SimpleTest.java index d13eecf..640cc69 100644 --- a/src/test/java/io/github/mapapire/SimpleTest.java +++ b/src/test/java/io/github/mapapire/SimpleTest.java @@ -1,79 +1,95 @@ package io.github.mapapire; -import io.github.mapapire.types.DaemonServer; import io.github.mapapire.types.QueryResult; -import java.io.InputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; +import java.util.concurrent.CompletableFuture; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -class SimpleTest { - private static final String CONFIG_FILE = "config.properties"; - private static DaemonServer creds; - - @BeforeAll - public static void setup() throws Exception { - Properties properties = new Properties(); - try (InputStream input = SimpleTest.class.getClassLoader().getResourceAsStream(CONFIG_FILE)) { - if (input == null) { - throw new IOException("Unable to find " + CONFIG_FILE); - } - properties.load(input); - } - - List keys = Arrays.asList("IBMI_HOST", "IBMI_USER", "IBMI_PASSWORD", "IBMI_PORT"); - Map secrets = new HashMap<>(); - for (String key : keys) { - String value = properties.getProperty(key); - if (value.equals("")) { - throw new Error(key + " not set in config.properties"); - } - secrets.put(key, value); - } +class SimpleTest extends MapepireTest { + @Test + void simpleTest() throws Exception { + SqlJob job = new SqlJob(); + job.connect(MapepireTest.creds).get(); - String host = secrets.get(keys.get(0)); - String user = secrets.get(keys.get(1)); - String password = secrets.get(keys.get(2)); - int port = Integer.parseInt(secrets.get(keys.get(3))); + Query query = job.query("select * from sample.department"); + QueryResult result = query.execute().get(); - creds = new DaemonServer(host, port, user, password, true, ""); + assertTrue(result.getIsDone()); + assertTrue(result.getData().size() > 0); - // TODO: Get certificate + job.close(); } @Test - void simpleTest() { + void pagingTest() throws Exception { SqlJob job = new SqlJob(); - try { - boolean isConnected = job.connect(creds).get().getSuccess(); - if (!isConnected) { - return; + job.connect(MapepireTest.creds).get(); + + Query query = job.query("select * from sample.department"); + QueryResult result = query.execute(5).get(); + while (true) { + assertTrue(result.getData().size() > 0); + + if (result.getIsDone()) { + break; } - } catch (Exception e) { - e.printStackTrace(); - return; + result = query.fetchMore(5).get(); } - Query query = job.query("select * from sample.department"); - QueryResult result; + query.close().get(); + job.close(); + } + + @Test + void errorTest() throws Exception { + SqlJob job = new SqlJob(); + job.connect(MapepireTest.creds).get(); + + Query query = job.query("select * from scooby"); + try { - result = query.execute().get(); + query.execute(5).get(); + throw new Exception("Exception not hit"); } catch (Exception e) { - e.printStackTrace(); - return; + assertEquals("[SQL0204] SCOOBY in " + creds.getUser().toUpperCase() + " type *FILE not found., 42704, -204", + e.getMessage()); } - assertTrue(result.getIsDone()); - assertTrue(result.getData().size() > 0); + query.close().get(); + job.close(); + } + + @Test + void multipleStatementsOneJobTest() throws Exception { + SqlJob job = new SqlJob(); + job.connect(MapepireTest.creds).get(); + + QueryResult resultA = job.query("select * from sample.department").execute().get(); + assertTrue(resultA.getIsDone()); + + QueryResult resultB = job.query("select * from sample.employee").execute().get(); + assertTrue(resultB.getIsDone()); + + job.close(); + } + + @Test + void multipleStatementsParallelOneJobTest() throws Exception { + SqlJob job = new SqlJob(); + job.connect(MapepireTest.creds).get(); + + CompletableFuture> resultAFuture = job.query("select * from sample.department").execute(); + CompletableFuture> resultBFuture = job.query("select * from sample.employee").execute(); + CompletableFuture.allOf(resultAFuture, resultBFuture).join(); + QueryResult resultA = resultAFuture.get(); + QueryResult resultB = resultBFuture.get(); + + assertTrue(resultA.getIsDone()); + assertTrue(resultB.getIsDone()); job.close(); }