mirror of
https://github.com/jlengrand/helidon.git
synced 2026-03-10 08:21:17 +00:00
DBClient integration tests for MySQL, MadiaDB, PostgreSQL and MS SQL (#2383)
* DBClient integration tests for MySQL, MadiaDB, PostgreSQL and MS SQL Server. * Changes requested in PR. * Fixed javadoc build issue. Signed-off-by: Tomas Kraus <Tomas.Kraus@oracle.com>
This commit is contained in:
@@ -57,10 +57,17 @@ public interface DbClient {
|
||||
*/
|
||||
<U, T extends Subscribable<U>> T execute(Function<DbExecute, T> executor);
|
||||
|
||||
/**
|
||||
* Name of the named statement used in database health checks.
|
||||
*/
|
||||
String PING_STATEMENT_NAME = "ping";
|
||||
|
||||
/**
|
||||
* Pings the database, completes when DB is up and ready, completes exceptionally if not.
|
||||
* Executes simple SQL query defined as {@code db.statements.ping} configuration property.
|
||||
*
|
||||
* @return stage that completes when the ping finished
|
||||
* @deprecated Use {@code io.helidon.dbclient.health.DbClientHealthCheck} instead.
|
||||
*/
|
||||
Single<Void> ping();
|
||||
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
package io.helidon.dbclient.health;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import io.helidon.common.reactive.Awaitable;
|
||||
import io.helidon.dbclient.DbClient;
|
||||
|
||||
import org.eclipse.microprofile.health.HealthCheck;
|
||||
@@ -26,18 +29,16 @@ import org.eclipse.microprofile.health.HealthCheckResponseBuilder;
|
||||
/**
|
||||
* Database health check.
|
||||
*/
|
||||
public final class DbClientHealthCheck implements HealthCheck {
|
||||
public abstract class DbClientHealthCheck implements HealthCheck {
|
||||
|
||||
private final DbClient dbClient;
|
||||
private final String name;
|
||||
|
||||
private DbClientHealthCheck(Builder builder) {
|
||||
this.dbClient = builder.database;
|
||||
this.name = builder.name;
|
||||
}
|
||||
/* Local logger instance. */
|
||||
private static final Logger LOGGER = Logger.getLogger(DbClientHealthCheck.class.getName());
|
||||
/* Default hHealth check timeout in seconds (to wait for statement execution response). */
|
||||
private static final int DEFAULT_TIMEOUT_SECONDS = 10;
|
||||
|
||||
/**
|
||||
* Create a health check for the database.
|
||||
* Create a health check with default settings for the database.
|
||||
* This health check will execute DML statement named {@code ping} to verify database status.
|
||||
*
|
||||
* @param dbClient A database that implements {@link io.helidon.dbclient.DbClient#ping()}
|
||||
* @return health check that can be used with
|
||||
@@ -58,39 +59,220 @@ public final class DbClientHealthCheck implements HealthCheck {
|
||||
return new Builder(dbClient);
|
||||
}
|
||||
|
||||
/* Helidon database client. */
|
||||
private final DbClient dbClient;
|
||||
/* Health check name. */
|
||||
private final String name;
|
||||
/* Health check timeout length (to wait for statement execution response). */
|
||||
private final long timeoutDuration;
|
||||
/* Health check timeout units (to wait for statement execution response). */
|
||||
private final TimeUnit timeoutUnit;
|
||||
|
||||
private DbClientHealthCheck(Builder builder) {
|
||||
this.dbClient = builder.database;
|
||||
this.name = builder.name;
|
||||
this.timeoutDuration = builder.timeoutDuration;
|
||||
this.timeoutUnit = builder.timeoutUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the ping statement.
|
||||
*
|
||||
* @return {@code Awaitable} instance to wait for
|
||||
*/
|
||||
protected abstract Awaitable<?> execPing();
|
||||
|
||||
@Override
|
||||
public HealthCheckResponse call() {
|
||||
HealthCheckResponseBuilder builder = HealthCheckResponse.builder()
|
||||
.name(name);
|
||||
HealthCheckResponseBuilder builder = HealthCheckResponse.builder().name(name);
|
||||
|
||||
try {
|
||||
dbClient.ping().await(10, TimeUnit.SECONDS);
|
||||
execPing().await(timeoutDuration, timeoutUnit);
|
||||
builder.up();
|
||||
} catch (Throwable e) {
|
||||
builder.down();
|
||||
builder.withData("ErrorMessage", e.getMessage());
|
||||
builder.withData("ErrorClass", e.getClass().getName());
|
||||
e.printStackTrace();
|
||||
LOGGER.log(Level.FINER, e, () -> String.format(
|
||||
"Database %s is not responding: %s", dbClient.dbType(), e.getMessage()));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
protected DbClient dbClient() {
|
||||
return dbClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Database health check which calls default DBClient's {@code ping} method.
|
||||
*/
|
||||
private static final class DbClientHealthCheckAsPing extends DbClientHealthCheck {
|
||||
|
||||
private DbClientHealthCheckAsPing(Builder builder) {
|
||||
super(builder);
|
||||
LOGGER.finest("Created an instance of DbClientHealthCheckAsPing");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Awaitable<Void> execPing() {
|
||||
return dbClient().ping();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Database health check which calls DBClient's {@code namedDml} method.
|
||||
*/
|
||||
private static final class DbClientHealthCheckAsNamedDml extends DbClientHealthCheck {
|
||||
|
||||
/* Name of the statement. */
|
||||
private final String statementName;
|
||||
|
||||
private DbClientHealthCheckAsNamedDml(Builder builder) {
|
||||
super(builder);
|
||||
this.statementName = builder.statementName;
|
||||
LOGGER.finest("Created an instance of DbClientHealthCheckAsNamedDml");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Awaitable<?> execPing() {
|
||||
return dbClient().execute(exec -> exec.namedDml(statementName));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Database health check which calls DBClient's {@code dml} method.
|
||||
*/
|
||||
private static final class DbClientHealthCheckAsDml extends DbClientHealthCheck {
|
||||
|
||||
/* Custom statement. */
|
||||
private final String statement;
|
||||
|
||||
private DbClientHealthCheckAsDml(Builder builder) {
|
||||
super(builder);
|
||||
this.statement = builder.statement;
|
||||
LOGGER.finest("Created an instance of DbClientHealthCheckAsDml");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Awaitable<?> execPing() {
|
||||
return dbClient().execute(exec -> exec.dml(statement));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Database health check which calls DBClient's {@code namedQuery} method.
|
||||
*/
|
||||
private static final class DbClientHealthCheckAsNamedQuery extends DbClientHealthCheck {
|
||||
|
||||
/* Name of the statement. */
|
||||
private final String statementName;
|
||||
|
||||
private DbClientHealthCheckAsNamedQuery(Builder builder) {
|
||||
super(builder);
|
||||
this.statementName = builder.statementName;
|
||||
LOGGER.finest("Created an instance of DbClientHealthCheckAsNamedQuery");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Awaitable<?> execPing() {
|
||||
return dbClient()
|
||||
.execute(exec -> exec.namedQuery(statementName).forEach(it -> {}));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Database health check which calls DBClient's {@code query} method.
|
||||
*/
|
||||
private static final class DbClientHealthCheckAsQuery extends DbClientHealthCheck {
|
||||
|
||||
/* Custom statement. */
|
||||
private final String statement;
|
||||
|
||||
private DbClientHealthCheckAsQuery(Builder builder) {
|
||||
super(builder);
|
||||
this.statement = builder.statement;
|
||||
LOGGER.finest("Created an instance of DbClientHealthCheckAsQuery");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Awaitable<?> execPing() {
|
||||
return dbClient()
|
||||
.execute(exec -> exec.query(statement).forEach(it -> {}));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Fluent API builder for {@link DbClientHealthCheck}.
|
||||
* Default health check setup will call named DML statement with name {@code ping}.
|
||||
* This named DML statement shall be configured in {@code statements} section
|
||||
* of the DBClient configuration file.
|
||||
*/
|
||||
public static final class Builder implements io.helidon.common.Builder<DbClientHealthCheck> {
|
||||
|
||||
/* Helidon database client. */
|
||||
private final DbClient database;
|
||||
/* Health check name. */
|
||||
private String name;
|
||||
/* Health check timeout length (to wait for statement execution response). */
|
||||
private long timeoutDuration;
|
||||
/* Health check timeout units (to wait for statement execution response). */
|
||||
private TimeUnit timeoutUnit;
|
||||
|
||||
// Those two boolean variables define 4 ways of query execution:
|
||||
//
|
||||
// +-----------+----------+--------+------------+-------+
|
||||
// | DbExecute | namedDML | dml | namedQuery | query |
|
||||
// +-----------+----------+--------+------------+-------+
|
||||
// | isDML | true | true | false | false |
|
||||
// | named | true | faslse | true | false |
|
||||
// +-----------+----------+--------+------------+-------+
|
||||
// The best performance optimized solution seems to be polymorphysm for part of check method.
|
||||
|
||||
/* Health check statement is DML when {@code true} and query when {@code false}. */
|
||||
private boolean isDML;
|
||||
/* Whether to use named statement or statement passed as an argument. */
|
||||
private boolean isNamedstatement;
|
||||
|
||||
/** Name of the statement. */
|
||||
private String statementName;
|
||||
/** Custom statement. */
|
||||
private String statement;
|
||||
|
||||
private Builder(DbClient database) {
|
||||
this.database = database;
|
||||
this.name = database.dbType();
|
||||
this.timeoutDuration = DEFAULT_TIMEOUT_SECONDS;
|
||||
this.timeoutUnit = TimeUnit.SECONDS;
|
||||
this.isDML = true;
|
||||
this.isNamedstatement = true;
|
||||
this.statementName = null;
|
||||
this.statement = null;
|
||||
}
|
||||
|
||||
// Defines polymorphysm for ping statement execution based on isDML and isNamedstatement values.
|
||||
// Default health check is to call DBClient's ping method (when no customization is set).
|
||||
@Override
|
||||
public DbClientHealthCheck build() {
|
||||
return new DbClientHealthCheck(this);
|
||||
if (isDML) {
|
||||
if (isNamedstatement) {
|
||||
return statementName == null
|
||||
? new DbClientHealthCheckAsPing(this) : new DbClientHealthCheckAsNamedDml(this);
|
||||
} else {
|
||||
return new DbClientHealthCheckAsDml(this);
|
||||
}
|
||||
} else {
|
||||
if (isNamedstatement && statementName == null) {
|
||||
statementName = DbClient.PING_STATEMENT_NAME;
|
||||
}
|
||||
return isNamedstatement
|
||||
? new DbClientHealthCheckAsNamedQuery(this) : new DbClientHealthCheckAsQuery(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,6 +286,66 @@ public final class DbClientHealthCheck implements HealthCheck {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set health check statement type to query.
|
||||
* Default health check statement type is DML.
|
||||
*
|
||||
* @return updated builder instance
|
||||
*/
|
||||
public Builder query() {
|
||||
this.isDML = false;
|
||||
this.isNamedstatement = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom statement name.
|
||||
* Default statement name value is {@code ping}.
|
||||
*
|
||||
* @param name custom statement name.
|
||||
* @return updated builder instance
|
||||
*/
|
||||
public Builder statementName(String name) {
|
||||
if (statement != null) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Can't use both statementName and statement methods in a single builder instance!");
|
||||
}
|
||||
this.isNamedstatement = true;
|
||||
this.statementName = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom statement.
|
||||
*
|
||||
* @param statement custom statement name.
|
||||
* @return updated builder instance
|
||||
*/
|
||||
public Builder statement(String statement) {
|
||||
if (statementName != null) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Can't use both statementName and statement methods in a single builder instance!");
|
||||
}
|
||||
this.isNamedstatement = false;
|
||||
this.statement = statement;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom timeout to wait for statement execution response.
|
||||
* Default value is {@code 10} seconds.
|
||||
*
|
||||
* @param duration the maximum time to wait for statement execution response
|
||||
* @param timeUnit the time unit of the timeout argument
|
||||
* @return updated builder instance
|
||||
*/
|
||||
public Builder timeout(long duration, TimeUnit timeUnit) {
|
||||
this.timeoutDuration = duration;
|
||||
this.timeoutUnit = timeUnit;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -149,12 +149,12 @@ class JdbcDbClient implements DbClient {
|
||||
@Override
|
||||
public T apply(Throwable t) {
|
||||
LOGGER.log(level,
|
||||
String.format("Transaction rollback: %s", t.getMessage()),
|
||||
t);
|
||||
t,
|
||||
() -> String.format("Transaction rollback: %s", t.getMessage()));
|
||||
execute.doRollback().exceptionally(t2 -> {
|
||||
LOGGER.log(level,
|
||||
String.format("Transaction rollback failed: %s", t2.getMessage()),
|
||||
t2);
|
||||
t2,
|
||||
() -> String.format("Transaction rollback failed: %s", t2.getMessage()));
|
||||
return null;
|
||||
});
|
||||
return null;
|
||||
@@ -190,8 +190,8 @@ class JdbcDbClient implements DbClient {
|
||||
execute.close();
|
||||
}).exceptionally(throwable -> {
|
||||
LOGGER.log(Level.WARNING,
|
||||
String.format("Execution failed: %s", throwable.getMessage()),
|
||||
throwable);
|
||||
throwable,
|
||||
() -> String.format("Execution failed: %s", throwable.getMessage()));
|
||||
execute.close();
|
||||
return null;
|
||||
});
|
||||
@@ -199,8 +199,8 @@ class JdbcDbClient implements DbClient {
|
||||
|
||||
result = result.onError(throwable -> {
|
||||
LOGGER.log(Level.FINEST,
|
||||
String.format("Execution failed: %s", throwable.getMessage()),
|
||||
throwable);
|
||||
throwable,
|
||||
() -> String.format("Execution failed: %s", throwable.getMessage()));
|
||||
execute.close();
|
||||
});
|
||||
|
||||
@@ -209,7 +209,7 @@ class JdbcDbClient implements DbClient {
|
||||
|
||||
@Override
|
||||
public Single<Void> ping() {
|
||||
return execute(exec -> exec.namedUpdate("ping"))
|
||||
return execute(exec -> exec.namedUpdate(PING_STATEMENT_NAME))
|
||||
.flatMapSingle(it -> Single.empty());
|
||||
}
|
||||
|
||||
@@ -372,7 +372,7 @@ class JdbcDbClient implements DbClient {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
LOGGER.log(Level.WARNING, String.format("Could not close connection: %s", e.getMessage()), e);
|
||||
LOGGER.log(Level.WARNING, e, () -> String.format("Could not close connection: %s", e.getMessage()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
18
dependencies/pom.xml
vendored
18
dependencies/pom.xml
vendored
@@ -79,6 +79,7 @@
|
||||
<version.lib.jsonp-impl>1.1.6</version.lib.jsonp-impl>
|
||||
<version.lib.junit>5.6.2</version.lib.junit>
|
||||
<version.lib.junit4>4.12</version.lib.junit4>
|
||||
<version.lib.mariadb-java-client>2.6.2</version.lib.mariadb-java-client>
|
||||
<version.lib.maven-wagon>2.10</version.lib.maven-wagon>
|
||||
<version.lib.microprofile-config>1.4</version.lib.microprofile-config>
|
||||
<version.lib.microprofile-health>2.2</version.lib.microprofile-health>
|
||||
@@ -93,6 +94,7 @@
|
||||
<version.lib.microprofile-reactive-streams-operators-core>1.0.1</version.lib.microprofile-reactive-streams-operators-core>
|
||||
<version.lib.mockito>2.23.4</version.lib.mockito>
|
||||
<version.lib.mongodb.reactivestreams>1.11.0</version.lib.mongodb.reactivestreams>
|
||||
<version.lib.mssql-jdbc>8.4.1.jre8</version.lib.mssql-jdbc>
|
||||
<version.lib.oracle.ojdbc10>19.3.0.0</version.lib.oracle.ojdbc10>
|
||||
<version.lib.mysql-connector-java>8.0.11</version.lib.mysql-connector-java>
|
||||
<version.lib.narayana>5.9.3.Final</version.lib.narayana>
|
||||
@@ -103,6 +105,7 @@
|
||||
<version.lib.opentracing.grpc>0.2.1</version.lib.opentracing.grpc>
|
||||
<version.lib.opentracing.tracerresolver>0.1.8</version.lib.opentracing.tracerresolver>
|
||||
<version.lib.persistence-api>2.2.3</version.lib.persistence-api>
|
||||
<version.lib.postgresql>42.2.16</version.lib.postgresql>
|
||||
<version.lib.prometheus>0.9.0</version.lib.prometheus>
|
||||
<version.lib.reactivestreams>1.0.3</version.lib.reactivestreams>
|
||||
<version.lib.slf4j>1.7.26</version.lib.slf4j>
|
||||
@@ -782,6 +785,21 @@
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${version.lib.mysql-connector-java}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mariadb.jdbc</groupId>
|
||||
<artifactId>mariadb-java-client</artifactId>
|
||||
<version>${version.lib.mariadb-java-client}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>${version.lib.postgresql}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
<version>${version.lib.mssql-jdbc}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.oracle.oci.sdk</groupId>
|
||||
<artifactId>oci-java-sdk-objectstorage</artifactId>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
package io.helidon.tests.integration.dbclient.common;
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
@@ -15,11 +13,13 @@ package io.helidon.tests.integration.dbclient.common;
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.helidon.tests.integration.dbclient.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import io.helidon.config.Config;
|
||||
@@ -36,10 +36,15 @@ public abstract class AbstractIT {
|
||||
/** Local logger instance. */
|
||||
private static final Logger LOGGER = Logger.getLogger(AbstractIT.class.getName());
|
||||
|
||||
public static final Config CONFIG = Config.create(ConfigSources.classpath("test.yaml"));
|
||||
public static final Config CONFIG = Config.create(ConfigSources.classpath(ConfigIT.configFile()));
|
||||
|
||||
public static final DbClient DB_CLIENT = initDbClient();
|
||||
|
||||
/**
|
||||
* Initialize database client.
|
||||
*
|
||||
* @return database client instance
|
||||
*/
|
||||
public static DbClient initDbClient() {
|
||||
Config dbConfig = CONFIG.get("db");
|
||||
return DbClient.builder(dbConfig).build();
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed 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 io.helidon.tests.integration.dbclient.common;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Configuration utilities.
|
||||
*/
|
||||
public class ConfigIT {
|
||||
|
||||
/** Local logger instance. */
|
||||
private static final Logger LOGGER = Logger.getLogger(ConfigIT.class.getName());
|
||||
|
||||
private static final String CONFIG_PROPERTY_NAME="io.helidon.tests.integration.dbclient.config";
|
||||
|
||||
private static final String DEFAULT_CONFIG_FILE="test.yaml";
|
||||
|
||||
/**
|
||||
* Retrieve configuration file from {@code io.helidon.tests.integration.dbclient.config}
|
||||
* property if exists.
|
||||
* Default {@code test.yaml} value is used when no property is set.
|
||||
*
|
||||
* @return tests configuration file name
|
||||
*/
|
||||
public static String configFile() {
|
||||
String configFile = System.getProperty(CONFIG_PROPERTY_NAME, DEFAULT_CONFIG_FILE);
|
||||
LOGGER.info(() -> String.format("Configuration file: %s", configFile));
|
||||
return configFile;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,13 +15,20 @@
|
||||
*/
|
||||
package io.helidon.tests.integration.dbclient.common.tests.health;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import io.helidon.config.Config;
|
||||
import io.helidon.dbclient.health.DbClientHealthCheck;
|
||||
|
||||
import org.eclipse.microprofile.health.HealthCheck;
|
||||
import org.eclipse.microprofile.health.HealthCheckResponse;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static io.helidon.tests.integration.dbclient.common.AbstractIT.CONFIG;
|
||||
import static io.helidon.tests.integration.dbclient.common.AbstractIT.DB_CLIENT;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
@@ -30,12 +37,31 @@ import static org.hamcrest.Matchers.equalTo;
|
||||
*/
|
||||
public class HealthCheckIT {
|
||||
|
||||
/** Local logger instance. */
|
||||
private static final Logger LOGGER = Logger.getLogger(HealthCheckIT.class.getName());
|
||||
|
||||
private static boolean pingDml = true;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
Config cfgPingDml = CONFIG.get("test.ping-dml");
|
||||
pingDml = cfgPingDml.exists() ? cfgPingDml.asBoolean().get() : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify health BASIC check implementation.
|
||||
* Verify health check implementation with default settings.
|
||||
*/
|
||||
@Test
|
||||
public void testHealthCheck() {
|
||||
HealthCheck check = DbClientHealthCheck.create(DB_CLIENT);
|
||||
LOGGER.log(Level.INFO, "Running test testHealthCheck");
|
||||
HealthCheck check;
|
||||
if (!pingDml) {
|
||||
LOGGER.log(Level.INFO, () -> String.format("Database %s does not support DML ping, using query", DB_CLIENT.dbType()));
|
||||
check = DbClientHealthCheck.builder(DB_CLIENT).query().build();
|
||||
} else {
|
||||
LOGGER.log(Level.INFO, () -> String.format("Database %s supports DML ping, using default method", DB_CLIENT.dbType()));
|
||||
check = DbClientHealthCheck.create(DB_CLIENT);
|
||||
}
|
||||
HealthCheckResponse response = check.call();
|
||||
HealthCheckResponse.State state = response.getState();
|
||||
assertThat("Healthcheck failed, response: " + response.getData(), state, equalTo(HealthCheckResponse.State.UP));
|
||||
@@ -46,8 +72,16 @@ public class HealthCheckIT {
|
||||
*/
|
||||
@Test
|
||||
public void testHealthCheckWithName() {
|
||||
LOGGER.log(Level.INFO, "Running test testHealthCheckWithName");
|
||||
final String hcName = "TestHC";
|
||||
HealthCheck check = DbClientHealthCheck.builder(DB_CLIENT).name(hcName).build();
|
||||
HealthCheck check;
|
||||
if (!pingDml) {
|
||||
LOGGER.log(Level.INFO, () -> String.format("Database %s does not support DML ping, using query", DB_CLIENT.dbType()));
|
||||
check = DbClientHealthCheck.builder(DB_CLIENT).name(hcName).query().build();
|
||||
} else {
|
||||
LOGGER.log(Level.INFO, () -> String.format("Database %s supports DML ping, using default method", DB_CLIENT.dbType()));
|
||||
check = DbClientHealthCheck.builder(DB_CLIENT).name(hcName).build();
|
||||
}
|
||||
HealthCheckResponse response = check.call();
|
||||
String name = response.getName();
|
||||
HealthCheckResponse.State state = response.getState();
|
||||
@@ -55,4 +89,71 @@ public class HealthCheckIT {
|
||||
assertThat(state, equalTo(HealthCheckResponse.State.UP));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify health check implementation using custom DML named statement.
|
||||
*/
|
||||
@Test
|
||||
public void testHealthCheckWithCustomNamedDML() {
|
||||
LOGGER.log(Level.INFO, "Running test testHealthCheckWithCustomNamedDML");
|
||||
if (!pingDml) {
|
||||
LOGGER.log(Level.INFO, () -> String.format("Database %s does not support DML ping, skipping this test", DB_CLIENT.dbType()));
|
||||
return;
|
||||
}
|
||||
HealthCheck check = DbClientHealthCheck.builder(DB_CLIENT).statementName("ping-dml").build();
|
||||
HealthCheckResponse response = check.call();
|
||||
HealthCheckResponse.State state = response.getState();
|
||||
assertThat("Healthcheck failed, response: " + response.getData(), state, equalTo(HealthCheckResponse.State.UP));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify health check implementation using custom DML statement.
|
||||
*/
|
||||
@Test
|
||||
public void testHealthCheckWithCustomDML() {
|
||||
LOGGER.log(Level.INFO, "Running test testHealthCheckWithCustomDML");
|
||||
if (!pingDml) {
|
||||
LOGGER.log(Level.INFO, () -> String.format("Database %s does not support DML ping, skipping this test", DB_CLIENT.dbType()));
|
||||
return;
|
||||
}
|
||||
Config cfgStatement = CONFIG.get("db.statements.ping-dml");
|
||||
assertThat("Missing ping-dml statement in database configuration!", cfgStatement.exists(), equalTo(true));
|
||||
String statement = cfgStatement.asString().get();
|
||||
assertThat("Missing ping-dml statement String in database configuration!", statement, is(notNullValue()));
|
||||
LOGGER.log(Level.INFO, () -> String.format("Using db.statements.ping-dml value %s", statement));
|
||||
HealthCheck check = DbClientHealthCheck.builder(DB_CLIENT).statement(statement).build();
|
||||
HealthCheckResponse response = check.call();
|
||||
HealthCheckResponse.State state = response.getState();
|
||||
assertThat("Healthcheck failed, response: " + response.getData(), state, equalTo(HealthCheckResponse.State.UP));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify health check implementation using custom query named statement.
|
||||
*/
|
||||
@Test
|
||||
public void testHealthCheckWithCustomNamedQuery() {
|
||||
LOGGER.log(Level.INFO, "Running test testHealthCheckWithCustomNamedQuery");
|
||||
HealthCheck check = DbClientHealthCheck.builder(DB_CLIENT).query().statementName("ping-query").build();
|
||||
HealthCheckResponse response = check.call();
|
||||
HealthCheckResponse.State state = response.getState();
|
||||
assertThat("Healthcheck failed, response: " + response.getData(), state, equalTo(HealthCheckResponse.State.UP));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify health check implementation using custom query statement.
|
||||
*/
|
||||
@Test
|
||||
public void testHealthCheckWithCustomQuery() {
|
||||
LOGGER.log(Level.INFO, "Running test testHealthCheckWithCustomQuery");
|
||||
Config cfgStatement = CONFIG.get("db.statements.ping-query");
|
||||
assertThat("Missing ping-query statement in database configuration!", cfgStatement.exists(), equalTo(true));
|
||||
String statement = cfgStatement.asString().get();
|
||||
assertThat("Missing ping-query statement String in database configuration!", statement, is(notNullValue()));
|
||||
LOGGER.log(Level.INFO, () -> String.format("Using db.statements.ping-query value %s", statement));
|
||||
HealthCheck check = DbClientHealthCheck.builder(DB_CLIENT).query().statement(statement).build();
|
||||
HealthCheckResponse response = check.call();
|
||||
HealthCheckResponse.State state = response.getState();
|
||||
assertThat("Healthcheck failed, response: " + response.getData(), state, equalTo(HealthCheckResponse.State.UP));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -34,12 +34,14 @@ import javax.json.JsonValue;
|
||||
import javax.json.stream.JsonParsingException;
|
||||
|
||||
import io.helidon.common.reactive.Multi;
|
||||
import io.helidon.config.Config;
|
||||
import io.helidon.dbclient.DbRow;
|
||||
import io.helidon.dbclient.health.DbClientHealthCheck;
|
||||
import io.helidon.health.HealthSupport;
|
||||
import io.helidon.webserver.Routing;
|
||||
import io.helidon.webserver.WebServer;
|
||||
|
||||
import org.eclipse.microprofile.health.HealthCheck;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -63,8 +65,13 @@ public class ServerHealthCheckIT {
|
||||
private static String URL;
|
||||
|
||||
private static Routing createRouting() {
|
||||
Config cfgPingDml = CONFIG.get("test.ping-dml");
|
||||
boolean pingDml = cfgPingDml.exists() ? cfgPingDml.asBoolean().get() : true;
|
||||
HealthCheck check = pingDml
|
||||
? DbClientHealthCheck.create(DB_CLIENT)
|
||||
: DbClientHealthCheck.builder(DB_CLIENT).query().build();
|
||||
final HealthSupport health = HealthSupport.builder()
|
||||
.addLiveness(DbClientHealthCheck.create(DB_CLIENT))
|
||||
.addLiveness(check)
|
||||
.build();
|
||||
return Routing.builder()
|
||||
.register(health) // Health at "/health"
|
||||
|
||||
@@ -32,12 +32,6 @@
|
||||
<name>Integration Tests: DB Client JDBC</name>
|
||||
|
||||
<properties>
|
||||
<mysql.port>3306</mysql.port>
|
||||
<mysql.host>127.0.0.1</mysql.host>
|
||||
<mysql.database>pokemon</mysql.database>
|
||||
<mysql.user>user</mysql.user>
|
||||
<mysql.password>password</mysql.password>
|
||||
<mysql.roootpw>root</mysql.roootpw>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -72,11 +66,6 @@
|
||||
<artifactId>slf4j-jdk14</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
@@ -97,12 +86,31 @@
|
||||
</testResource>
|
||||
</testResources>
|
||||
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
<version>0.33.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${version.plugin.surefire}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>${version.plugin.surefire}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${version.plugin.surefire}</version>
|
||||
<configuration>
|
||||
<skipTests>true</skipTests>
|
||||
</configuration>
|
||||
@@ -111,7 +119,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>${version.plugin.surefire}</version>
|
||||
<configuration>
|
||||
<parallel>methods</parallel>
|
||||
<threadCount>10</threadCount>
|
||||
@@ -126,7 +133,8 @@
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>io.helidon.tests.integration.dbclient.jdbc.init.*IT</include>
|
||||
<include>io.helidon.tests.integration.dbclient.jdbc.init.CheckIT</include>
|
||||
<include>io.helidon.tests.integration.dbclient.jdbc.init.InitIT</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</execution>
|
||||
@@ -174,6 +182,315 @@
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>mysql</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>mysql</name>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<db.port>3306</db.port>
|
||||
<db.host>127.0.0.1</db.host>
|
||||
<db.database>pokemon</db.database>
|
||||
<db.user>user</db.user>
|
||||
<db.password>password</db.password>
|
||||
<db.roootpw>root</db.roootpw>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<io.helidon.tests.integration.dbclient.config>mysql.yaml</io.helidon.tests.integration.dbclient.config>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<images>
|
||||
<image>
|
||||
<name>mysql:8</name>
|
||||
<alias>mysql</alias>
|
||||
<run>
|
||||
<env>
|
||||
<MYSQL_USER>${db.user}</MYSQL_USER>
|
||||
<MYSQL_PASSWORD>${db.password}</MYSQL_PASSWORD>
|
||||
<MYSQL_ROOT_PASSWORD>${db.roootpw}</MYSQL_ROOT_PASSWORD>
|
||||
<MYSQL_DATABASE>${db.database}</MYSQL_DATABASE>
|
||||
</env>
|
||||
<hostname>${db.host}</hostname>
|
||||
<ports>
|
||||
<port>${db.host}:${db.port}:3306</port>
|
||||
</ports>
|
||||
<wait>
|
||||
<log>MySQL server is up an running</log>
|
||||
<tcp>
|
||||
<host>127.0.0.1</host>
|
||||
<ports>
|
||||
<port>${db.port}</port>
|
||||
</ports>
|
||||
</tcp>
|
||||
<time>120000</time>
|
||||
</wait>
|
||||
</run>
|
||||
</image>
|
||||
</images>
|
||||
<showLogs>true</showLogs>
|
||||
<startParallel>false</startParallel>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>mariadb</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>mariadb</name>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<db.port>3306</db.port>
|
||||
<db.host>127.0.0.1</db.host>
|
||||
<db.database>pokemon</db.database>
|
||||
<db.user>user</db.user>
|
||||
<db.password>password</db.password>
|
||||
<db.roootpw>root</db.roootpw>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.mariadb.jdbc</groupId>
|
||||
<artifactId>mariadb-java-client</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<io.helidon.tests.integration.dbclient.config>mariadb.yaml</io.helidon.tests.integration.dbclient.config>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<images>
|
||||
<image>
|
||||
<name>mariadb</name>
|
||||
<alias>mariadb</alias>
|
||||
<run>
|
||||
<env>
|
||||
<MYSQL_USER>${db.user}</MYSQL_USER>
|
||||
<MYSQL_PASSWORD>${db.password}</MYSQL_PASSWORD>
|
||||
<MYSQL_ROOT_PASSWORD>${db.roootpw}</MYSQL_ROOT_PASSWORD>
|
||||
<MYSQL_DATABASE>${db.database}</MYSQL_DATABASE>
|
||||
</env>
|
||||
<hostname>${db.host}</hostname>
|
||||
<ports>
|
||||
<port>${db.host}:${db.port}:3306</port>
|
||||
</ports>
|
||||
<wait>
|
||||
<log>MySQL server is up an running</log>
|
||||
<tcp>
|
||||
<host>127.0.0.1</host>
|
||||
<ports>
|
||||
<port>${db.port}</port>
|
||||
</ports>
|
||||
</tcp>
|
||||
<time>120000</time>
|
||||
</wait>
|
||||
</run>
|
||||
</image>
|
||||
</images>
|
||||
<showLogs>true</showLogs>
|
||||
<startParallel>false</startParallel>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>pgsql</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>pgsql</name>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<db.port>5432</db.port>
|
||||
<db.host>127.0.0.1</db.host>
|
||||
<db.database>pokemon</db.database>
|
||||
<db.user>user</db.user>
|
||||
<db.password>password</db.password>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<io.helidon.tests.integration.dbclient.config>pgsql.yaml</io.helidon.tests.integration.dbclient.config>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<images>
|
||||
<image>
|
||||
<name>postgres</name>
|
||||
<alias>postgres</alias>
|
||||
<run>
|
||||
<env>
|
||||
<POSTGRES_USER>${db.user}</POSTGRES_USER>
|
||||
<POSTGRES_PASSWORD>${db.password}</POSTGRES_PASSWORD>
|
||||
<POSTGRES_DB>${db.database}</POSTGRES_DB>
|
||||
</env>
|
||||
<hostname>${db.host}</hostname>
|
||||
<ports>
|
||||
<port>${db.host}:${db.port}:5432</port>
|
||||
</ports>
|
||||
<wait>
|
||||
<log>MySQL server is up an running</log>
|
||||
<tcp>
|
||||
<host>127.0.0.1</host>
|
||||
<ports>
|
||||
<port>${db.port}</port>
|
||||
</ports>
|
||||
</tcp>
|
||||
<time>120000</time>
|
||||
</wait>
|
||||
</run>
|
||||
</image>
|
||||
</images>
|
||||
<showLogs>true</showLogs>
|
||||
<startParallel>false</startParallel>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>mssql</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>mssql</name>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<accept.eula>Y</accept.eula>
|
||||
<db.sa.password>MsH4sN0r00t</db.sa.password>
|
||||
<db.port>1433</db.port>
|
||||
<db.host>127.0.0.1</db.host>
|
||||
<db.database>pokemon</db.database>
|
||||
<db.user>test_user</db.user>
|
||||
<db.password>P4ss_W0rd</db.password>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.sqlserver</groupId>
|
||||
<artifactId>mssql-jdbc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<io.helidon.tests.integration.dbclient.config>mssql.yaml</io.helidon.tests.integration.dbclient.config>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<images>
|
||||
<image>
|
||||
<name>mcr.microsoft.com/mssql/server:2017-latest</name>
|
||||
<alias>mssql</alias>
|
||||
<run>
|
||||
<env>
|
||||
<ACCEPT_EULA>${accept.eula}</ACCEPT_EULA>
|
||||
<SA_PASSWORD>${db.sa.password}</SA_PASSWORD>
|
||||
</env>
|
||||
<hostname>${db.host}</hostname>
|
||||
<ports>
|
||||
<port>${db.host}:${db.port}:1433</port>
|
||||
</ports>
|
||||
<wait>
|
||||
<log>SQL server is up an running</log>
|
||||
<tcp>
|
||||
<host>127.0.0.1</host>
|
||||
<ports>
|
||||
<port>${db.port}</port>
|
||||
</ports>
|
||||
</tcp>
|
||||
<time>120000</time>
|
||||
</wait>
|
||||
</run>
|
||||
</image>
|
||||
</images>
|
||||
<showLogs>true</showLogs>
|
||||
<startParallel>false</startParallel>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<parallel>methods</parallel>
|
||||
<threadCount>10</threadCount>
|
||||
</configuration>
|
||||
<executions>
|
||||
<!-- Wait for database to start up and initialize database-->
|
||||
<execution>
|
||||
<id>init</id>
|
||||
<phase>integration-test</phase>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>io.helidon.tests.integration.dbclient.jdbc.init.CheckMsSqlIT</include>
|
||||
<include>io.helidon.tests.integration.dbclient.jdbc.init.InitIT</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<!--
|
||||
mvn -pl common,jdbc -Pdebug,docker install \
|
||||
-Dit.jdbc.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8787 -Xnoagent -Djava.compiler=NONE" \
|
||||
@@ -227,7 +544,6 @@
|
||||
<plugin>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
<version>0.31.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>start</id>
|
||||
@@ -244,38 +560,6 @@
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<images>
|
||||
<image>
|
||||
<name>mysql:8</name>
|
||||
<alias>mysql</alias>
|
||||
<run>
|
||||
<env>
|
||||
<MYSQL_USER>${mysql.user}</MYSQL_USER>
|
||||
<MYSQL_PASSWORD>${mysql.password}</MYSQL_PASSWORD>
|
||||
<MYSQL_ROOT_PASSWORD>${mysql.roootpw}</MYSQL_ROOT_PASSWORD>
|
||||
<MYSQL_DATABASE>${mysql.database}</MYSQL_DATABASE>
|
||||
</env>
|
||||
<hostname>${mysql.host}</hostname>
|
||||
<ports>
|
||||
<port>${mysql.host}:${mysql.port}:3306</port>
|
||||
</ports>
|
||||
<wait>
|
||||
<log>MySQL server is up an running</log>
|
||||
<tcp>
|
||||
<host>127.0.0.1</host>
|
||||
<ports>
|
||||
<port>${mysql.port}</port>
|
||||
</ports>
|
||||
</tcp>
|
||||
<time>120000</time>
|
||||
</wait>
|
||||
</run>
|
||||
</image>
|
||||
</images>
|
||||
<showLogs>true</showLogs>
|
||||
<startParallel>false</startParallel>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -17,12 +17,14 @@ package io.helidon.tests.integration.dbclient.jdbc.init;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import io.helidon.config.Config;
|
||||
import io.helidon.config.ConfigSources;
|
||||
import io.helidon.tests.integration.dbclient.common.ConfigIT;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -41,7 +43,7 @@ public class CheckIT {
|
||||
private static final Logger LOGGER = Logger.getLogger(CheckIT.class.getName());
|
||||
|
||||
/** Test configuration. */
|
||||
public static final Config CONFIG = Config.create(ConfigSources.classpath("test.yaml"));
|
||||
public static final Config CONFIG = Config.create(ConfigSources.classpath(ConfigIT.configFile()));
|
||||
|
||||
/** Timeout in seconds to wait for database to come up. */
|
||||
private static final int TIMEOUT = 60;
|
||||
@@ -69,6 +71,7 @@ public class CheckIT {
|
||||
connected = true;
|
||||
return;
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.info(() -> String.format("Connection check: %s", ex.getMessage()));
|
||||
if (System.currentTimeMillis() > endTm) {
|
||||
return;
|
||||
}
|
||||
@@ -85,14 +88,14 @@ public class CheckIT {
|
||||
/**
|
||||
* Store database connection configuration and build {@link Connection} instance.
|
||||
*/
|
||||
private static final class ConnectionBuilder implements Consumer<Config> {
|
||||
static final class ConnectionBuilder implements Consumer<Config> {
|
||||
|
||||
private boolean hasConfig;
|
||||
private String url;
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
private ConnectionBuilder() {
|
||||
ConnectionBuilder() {
|
||||
hasConfig = false;
|
||||
}
|
||||
|
||||
@@ -104,7 +107,7 @@ public class CheckIT {
|
||||
hasConfig = true;
|
||||
}
|
||||
|
||||
private Connection createConnection() throws SQLException {
|
||||
Connection createConnection() throws SQLException {
|
||||
if (!hasConfig) {
|
||||
fail("No db.connection configuration node was found.");
|
||||
}
|
||||
@@ -143,11 +146,21 @@ public class CheckIT {
|
||||
public void testDmlStatementExecution() throws SQLException {
|
||||
ConnectionBuilder builder = new ConnectionBuilder();
|
||||
String ping = CONFIG.get("db.statements.ping").asString().get();
|
||||
Config cfgPingDml = CONFIG.get("test.ping-dml");
|
||||
boolean pingDml = cfgPingDml.exists() ? cfgPingDml.asBoolean().get() : true;
|
||||
CONFIG.get("db.connection").ifExists(builder);
|
||||
Connection conn = builder.createConnection();
|
||||
int result = conn.createStatement().executeUpdate(ping);
|
||||
assertThat(result, equalTo(0));
|
||||
LOGGER.info(() -> String.format("Command ping result: %d", result));
|
||||
if (pingDml) {
|
||||
int result = conn.createStatement().executeUpdate(ping);
|
||||
assertThat(result, equalTo(0));
|
||||
LOGGER.info(() -> String.format("Command ping result: %d", result));
|
||||
} else {
|
||||
ResultSet rs = conn.createStatement().executeQuery(ping);
|
||||
rs.next();
|
||||
int result = rs.getInt(1);
|
||||
assertThat(result, equalTo(0));
|
||||
LOGGER.info(() -> String.format("Command ping result: %d", result));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* Licensed 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 io.helidon.tests.integration.dbclient.jdbc.init;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import io.helidon.config.Config;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static io.helidon.tests.integration.dbclient.jdbc.init.CheckIT.CONFIG;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* Check minimal functionality needed before running database schema initialization.
|
||||
* First test class being executed after database startup.
|
||||
*/
|
||||
public class CheckMsSqlIT {
|
||||
|
||||
/** Local logger instance. */
|
||||
private static final Logger LOGGER = Logger.getLogger(CheckIT.class.getName());
|
||||
|
||||
/** Timeout in seconds to wait for database to come up. */
|
||||
private static final int TIMEOUT = 60;
|
||||
|
||||
/** Database connection. */
|
||||
private static Connection conn = null;
|
||||
|
||||
/**
|
||||
* Wait until database starts up when its configuration node is available.
|
||||
*/
|
||||
private static final class ConnectionCheck implements Consumer<Config> {
|
||||
|
||||
private boolean connected;
|
||||
|
||||
private ConnectionCheck() {
|
||||
connected = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Config config) {
|
||||
String url = config.get("sa-url").asString().get();
|
||||
String username = config.get("sa-user").asString().get();
|
||||
String password = config.get("sa-password").asString().get();
|
||||
long endTm = 1000 * TIMEOUT + System.currentTimeMillis();
|
||||
while (true) {
|
||||
try {
|
||||
conn = DriverManager.getConnection(url, username, password);
|
||||
connected = true;
|
||||
return;
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.info(() -> String.format("Connection check: %s", ex.getMessage()));
|
||||
if (System.currentTimeMillis() > endTm) {
|
||||
conn = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean connected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create user and database and set permissions.
|
||||
*/
|
||||
private static final class DbInit implements Consumer<Config> {
|
||||
|
||||
@Override
|
||||
public void accept(Config config) {
|
||||
if (conn == null) {
|
||||
fail("Database connection is not available!");
|
||||
}
|
||||
String username = config.get("username").asString().get();
|
||||
String password = config.get("password").asString().get();
|
||||
String database = CheckIT.CONFIG.get("test.db-database").asString().get();
|
||||
try {
|
||||
Statement stmt = conn.createStatement();
|
||||
final int dbCount = stmt.executeUpdate(String.format("EXEC sp_configure 'CONTAINED DATABASE AUTHENTICATION', 1", database));
|
||||
LOGGER.log(Level.INFO, () -> String.format("Executed EXEC statement. %d records modified.", dbCount));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.WARNING, "Could not configure database:", ex);
|
||||
} try {
|
||||
Statement stmt = conn.createStatement();
|
||||
final int dbCount = stmt.executeUpdate(String.format("RECONFIGURE", database));
|
||||
LOGGER.log(Level.INFO, () -> String.format("Executed RECONFIGURE statement. %d records modified.", dbCount));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.WARNING, "Could not reconfigure database:", ex);
|
||||
} try {
|
||||
Statement stmt = conn.createStatement();
|
||||
final int dbCount = stmt.executeUpdate(String.format("CREATE DATABASE %s CONTAINMENT = PARTIAL", database));
|
||||
LOGGER.log(Level.INFO, () -> String.format("Executed CREATE DATABASE statement. %d records modified.", dbCount));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.WARNING, "Could not create database:", ex);
|
||||
} try {
|
||||
Statement stmt = conn.createStatement();
|
||||
final int useCount = stmt.executeUpdate(String.format("USE %s", database));
|
||||
LOGGER.log(Level.INFO, () -> String.format("Executed USE statement. %d records modified.", useCount));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.WARNING, "Could not use database:", ex);
|
||||
} try {
|
||||
Statement stmt = conn.createStatement();//"CREATE USER ? WITH PASSWORD = ?");
|
||||
final int userCount = stmt.executeUpdate(String.format("CREATE USER %s WITH PASSWORD = '%s'", username, password));
|
||||
LOGGER.log(Level.INFO, () -> String.format("Executed CREATE USER statement. %d records modified.", userCount));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.WARNING, "Could not create database user:", ex);
|
||||
} try {
|
||||
Statement stmt = conn.createStatement();//"CREATE USER ? WITH PASSWORD = ?");
|
||||
final int userCount = stmt.executeUpdate(String.format("GRANT ALL TO %s", username));
|
||||
LOGGER.log(Level.INFO, () -> String.format("Executed GRANT statement. %d records modified.", userCount));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.WARNING, "Could not grant database privilegs to user:", ex);
|
||||
} try {
|
||||
Statement stmt = conn.createStatement();//"CREATE USER ? WITH PASSWORD = ?");
|
||||
final int userCount = stmt.executeUpdate(String.format("GRANT CONTROL ON SCHEMA::dbo TO %s", username));
|
||||
LOGGER.log(Level.INFO, () -> String.format("Executed GRANT statement. %d records modified.", userCount));
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.WARNING, "Could not grant database privilegs to user:", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for database server to start.
|
||||
*/
|
||||
private static void waitForStart() {
|
||||
ConnectionCheck check = new ConnectionCheck();
|
||||
CheckIT.CONFIG.get("test").ifExists(check);
|
||||
if (!check.connected()) {
|
||||
fail("Database startup failed!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize database user.
|
||||
*/
|
||||
private static void initDb() {
|
||||
if (conn == null) {
|
||||
fail("Database connection is not available!");
|
||||
}
|
||||
DbInit init = new DbInit();
|
||||
CheckIT.CONFIG.get("db.connection").ifExists(init);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup database for tests.
|
||||
* Wait for database to start and create user and database for tests.
|
||||
* Returns after ping query completed successfully or timeout passed.
|
||||
*/
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
waitForStart();
|
||||
initDb();
|
||||
if (conn != null) {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.WARNING, "Could not close database connection:", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple test to verify that DML query execution works.
|
||||
* Used before running database schema initialization.
|
||||
*
|
||||
* @throws SQLException when database query failed
|
||||
*/
|
||||
@Test
|
||||
public void testDmlStatementExecution() throws SQLException {
|
||||
CheckIT.ConnectionBuilder builder = new CheckIT.ConnectionBuilder();
|
||||
String ping = CONFIG.get("db.statements.ping").asString().get();
|
||||
Config cfgPingDml = CONFIG.get("test.ping-dml");
|
||||
boolean pingDml = cfgPingDml.exists() ? cfgPingDml.asBoolean().get() : true;
|
||||
CONFIG.get("db.connection").ifExists(builder);
|
||||
Connection conn = builder.createConnection();
|
||||
if (pingDml) {
|
||||
int result = conn.createStatement().executeUpdate(ping);
|
||||
assertThat(result, equalTo(0));
|
||||
LOGGER.info(() -> String.format("Command ping result: %d", result));
|
||||
} else {
|
||||
ResultSet rs = conn.createStatement().executeQuery(ping);
|
||||
rs.next();
|
||||
int result = rs.getInt(1);
|
||||
assertThat(result, equalTo(0));
|
||||
LOGGER.info(() -> String.format("Command ping result: %d", result));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#
|
||||
# Copyright (c) 2019, 2020 Oracle and/or its affiliates.
|
||||
#
|
||||
# Licensed 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.
|
||||
#
|
||||
|
||||
server:
|
||||
port: 0
|
||||
host: 0.0.0.0
|
||||
|
||||
db:
|
||||
source: jdbc
|
||||
connection:
|
||||
url: jdbc:mariadb://${db.host}:${db.port}/${db.database}?useSSL=false&allowPublicKeyRetrieval=true
|
||||
username: ${db.user}
|
||||
password: ${db.password}
|
||||
statements:
|
||||
# required ping statement
|
||||
ping: "DO 0"
|
||||
# custom DML ping statement
|
||||
ping-dml: "DO 0"
|
||||
# custom query ping statement
|
||||
ping-query: "SELECT 0"
|
||||
# database schema initialization statements
|
||||
create-types: "CREATE TABLE Types (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)"
|
||||
create-pokemons: "CREATE TABLE Pokemons (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)"
|
||||
create-poketypes: "CREATE TABLE PokemonTypes (id_pokemon INTEGER NOT NULL REFERENCES Pokemons(id), id_type INTEGER NOT NULL REFERENCES Types(id))"
|
||||
# database schema cleanup statements
|
||||
drop-types: "DROP TABLE Types"
|
||||
drop-pokemons: "DROP TABLE Pokemons"
|
||||
drop-poketypes: "DROP TABLE PokemonTypes"
|
||||
# data initialization statements
|
||||
insert-type: "INSERT INTO Types(id, name) VALUES(?, ?)"
|
||||
insert-pokemon: "INSERT INTO Pokemons(id, name) VALUES(?, ?)"
|
||||
insert-poketype: "INSERT INTO PokemonTypes(id_pokemon, id_type) VALUES(?, ?)"
|
||||
# data initialization verification statements
|
||||
select-types: "SELECT id, name FROM Types"
|
||||
select-pokemons: "SELECT id, name FROM Pokemons"
|
||||
select-poketypes: "SELECT id_pokemon, id_type FROM PokemonTypes p WHERE id_pokemon = ?"
|
||||
# data cleanup verification statements
|
||||
select-poketypes-all: "SELECT id_pokemon, id_type FROM PokemonTypes"
|
||||
# retrieve max. Pokemon ID
|
||||
select-max-id: "SELECT MAX(id) FROM Pokemons"
|
||||
# test queries
|
||||
select-pokemon-named-arg: "SELECT id, name FROM Pokemons WHERE name=:name"
|
||||
select-pokemon-order-arg: "SELECT id, name FROM Pokemons WHERE name=?"
|
||||
# test DML insert
|
||||
insert-pokemon-named-arg: "INSERT INTO Pokemons(id, name) VALUES(:id, :name)"
|
||||
insert-pokemon-order-arg: "INSERT INTO Pokemons(id, name) VALUES(?, ?)"
|
||||
# Pokemon mapper uses reverse order of indexed arguments
|
||||
insert-pokemon-order-arg-rev: "INSERT INTO Pokemons(name, id) VALUES(?, ?)"
|
||||
# test DML update
|
||||
select-pokemon-by-id: "SELECT id, name FROM Pokemons WHERE id=?"
|
||||
update-pokemon-named-arg: "UPDATE Pokemons SET name=:name WHERE id=:id"
|
||||
update-pokemon-order-arg: "UPDATE Pokemons SET name=? WHERE id=?"
|
||||
# test DML delete
|
||||
delete-pokemon-named-arg: "DELETE FROM Pokemons WHERE id=:id"
|
||||
delete-pokemon-order-arg: "DELETE FROM Pokemons WHERE id=?"
|
||||
# Pokemon mapper uses full list of attributes
|
||||
delete-pokemon-full-named-arg: "DELETE FROM Pokemons WHERE name=:name AND id=:id"
|
||||
delete-pokemon-full-order-arg: "DELETE FROM Pokemons WHERE name=? AND id=?"
|
||||
# test DbStatementQuery methods
|
||||
select-pokemons-idrng-named-arg: "SELECT id, name FROM Pokemons WHERE id > :idmin AND id < :idmax"
|
||||
select-pokemons-idrng-order-arg: "SELECT id, name FROM Pokemons WHERE id > ? AND id < ?"
|
||||
# Test query with both named and ordered parameters (shall cause an exception)
|
||||
select-pokemons-error-arg: "SELECT id, name FROM Pokemons WHERE id > :id AND name = ?"
|
||||
|
||||
# Tests configuration
|
||||
test:
|
||||
# Whether database supports ping statement as DML (default value is true)
|
||||
#ping-dml: true
|
||||
@@ -0,0 +1,89 @@
|
||||
#
|
||||
# Copyright (c) 2019, 2020 Oracle and/or its affiliates.
|
||||
#
|
||||
# Licensed 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.
|
||||
#
|
||||
|
||||
server:
|
||||
port: 0
|
||||
host: 0.0.0.0
|
||||
|
||||
db:
|
||||
source: jdbc
|
||||
connection:
|
||||
url: jdbc:sqlserver://${db.host}:${db.port};databaseName=${db.database}
|
||||
username: ${db.user}
|
||||
password: ${db.password}
|
||||
statements:
|
||||
# required ping statement
|
||||
ping: "SELECT 0"
|
||||
# custom query ping statement
|
||||
ping-query: "SELECT 0"
|
||||
# database schema initialization statements
|
||||
create-types: "CREATE TABLE Types (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)"
|
||||
create-pokemons: "CREATE TABLE Pokemons (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)"
|
||||
create-poketypes: "CREATE TABLE PokemonTypes (id_pokemon INTEGER NOT NULL REFERENCES Pokemons(id), id_type INTEGER NOT NULL REFERENCES Types(id))"
|
||||
# database schema cleanup statements
|
||||
drop-types: "DROP TABLE Types"
|
||||
drop-pokemons: "DROP TABLE Pokemons"
|
||||
drop-poketypes: "DROP TABLE PokemonTypes"
|
||||
# data initialization statements
|
||||
insert-type: "INSERT INTO Types(id, name) VALUES(?, ?)"
|
||||
insert-pokemon: "INSERT INTO Pokemons(id, name) VALUES(?, ?)"
|
||||
insert-poketype: "INSERT INTO PokemonTypes(id_pokemon, id_type) VALUES(?, ?)"
|
||||
# data initialization verification statements
|
||||
select-types: "SELECT id, name FROM Types"
|
||||
select-pokemons: "SELECT id, name FROM Pokemons"
|
||||
select-poketypes: "SELECT id_pokemon, id_type FROM PokemonTypes p WHERE id_pokemon = ?"
|
||||
# data cleanup verification statements
|
||||
select-poketypes-all: "SELECT id_pokemon, id_type FROM PokemonTypes"
|
||||
# retrieve max. Pokemon ID
|
||||
select-max-id: "SELECT MAX(id) FROM Pokemons"
|
||||
# test queries
|
||||
select-pokemon-named-arg: "SELECT id, name FROM Pokemons WHERE name=:name"
|
||||
select-pokemon-order-arg: "SELECT id, name FROM Pokemons WHERE name=?"
|
||||
# test DML insert
|
||||
insert-pokemon-named-arg: "INSERT INTO Pokemons(id, name) VALUES(:id, :name)"
|
||||
insert-pokemon-order-arg: "INSERT INTO Pokemons(id, name) VALUES(?, ?)"
|
||||
# Pokemon mapper uses reverse order of indexed arguments
|
||||
insert-pokemon-order-arg-rev: "INSERT INTO Pokemons(name, id) VALUES(?, ?)"
|
||||
# test DML update
|
||||
select-pokemon-by-id: "SELECT id, name FROM Pokemons WHERE id=?"
|
||||
update-pokemon-named-arg: "UPDATE Pokemons SET name=:name WHERE id=:id"
|
||||
update-pokemon-order-arg: "UPDATE Pokemons SET name=? WHERE id=?"
|
||||
# test DML delete
|
||||
delete-pokemon-named-arg: "DELETE FROM Pokemons WHERE id=:id"
|
||||
delete-pokemon-order-arg: "DELETE FROM Pokemons WHERE id=?"
|
||||
# Pokemon mapper uses full list of attributes
|
||||
delete-pokemon-full-named-arg: "DELETE FROM Pokemons WHERE name=:name AND id=:id"
|
||||
delete-pokemon-full-order-arg: "DELETE FROM Pokemons WHERE name=? AND id=?"
|
||||
# test DbStatementQuery methods
|
||||
select-pokemons-idrng-named-arg: "SELECT id, name FROM Pokemons WHERE id > :idmin AND id < :idmax"
|
||||
select-pokemons-idrng-order-arg: "SELECT id, name FROM Pokemons WHERE id > ? AND id < ?"
|
||||
# Test query with both named and ordered parameters (shall cause an exception)
|
||||
select-pokemons-error-arg: "SELECT id, name FROM Pokemons WHERE id > :id AND name = ?"
|
||||
|
||||
# Tests configuration
|
||||
test:
|
||||
## Microsoft SQL Server specific setup
|
||||
# SQL database administrator's user name
|
||||
sa-user: sa
|
||||
# SQL database administrator's password
|
||||
sa-password: ${db.sa.password}
|
||||
# Sql database URL for administrator
|
||||
sa-url: jdbc:sqlserver://${db.host}:${db.port}
|
||||
# SQL database name (will be created and granted to regular test user)
|
||||
db-database: ${db.database}
|
||||
|
||||
# Whether database supports ping statement as DML (default value is true)
|
||||
ping-dml: false
|
||||
@@ -0,0 +1,81 @@
|
||||
#
|
||||
# Copyright (c) 2019, 2020 Oracle and/or its affiliates.
|
||||
#
|
||||
# Licensed 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.
|
||||
#
|
||||
|
||||
server:
|
||||
port: 0
|
||||
host: 0.0.0.0
|
||||
|
||||
db:
|
||||
source: jdbc
|
||||
connection:
|
||||
url: jdbc:mysql://${db.host}:${db.port}/${db.database}?useSSL=false&allowPublicKeyRetrieval=true
|
||||
username: ${db.user}
|
||||
password: ${db.password}
|
||||
statements:
|
||||
# required ping statement
|
||||
ping: "DO 0"
|
||||
# custom DML ping statement
|
||||
ping-dml: "DO 0"
|
||||
# custom query ping statement
|
||||
ping-query: "SELECT 0"
|
||||
# database schema initialization statements
|
||||
create-types: "CREATE TABLE Types (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)"
|
||||
create-pokemons: "CREATE TABLE Pokemons (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)"
|
||||
create-poketypes: "CREATE TABLE PokemonTypes (id_pokemon INTEGER NOT NULL REFERENCES Pokemons(id), id_type INTEGER NOT NULL REFERENCES Types(id))"
|
||||
# database schema cleanup statements
|
||||
drop-types: "DROP TABLE Types"
|
||||
drop-pokemons: "DROP TABLE Pokemons"
|
||||
drop-poketypes: "DROP TABLE PokemonTypes"
|
||||
# data initialization statements
|
||||
insert-type: "INSERT INTO Types(id, name) VALUES(?, ?)"
|
||||
insert-pokemon: "INSERT INTO Pokemons(id, name) VALUES(?, ?)"
|
||||
insert-poketype: "INSERT INTO PokemonTypes(id_pokemon, id_type) VALUES(?, ?)"
|
||||
# data initialization verification statements
|
||||
select-types: "SELECT id, name FROM Types"
|
||||
select-pokemons: "SELECT id, name FROM Pokemons"
|
||||
select-poketypes: "SELECT id_pokemon, id_type FROM PokemonTypes p WHERE id_pokemon = ?"
|
||||
# data cleanup verification statements
|
||||
select-poketypes-all: "SELECT id_pokemon, id_type FROM PokemonTypes"
|
||||
# retrieve max. Pokemon ID
|
||||
select-max-id: "SELECT MAX(id) FROM Pokemons"
|
||||
# test queries
|
||||
select-pokemon-named-arg: "SELECT id, name FROM Pokemons WHERE name=:name"
|
||||
select-pokemon-order-arg: "SELECT id, name FROM Pokemons WHERE name=?"
|
||||
# test DML insert
|
||||
insert-pokemon-named-arg: "INSERT INTO Pokemons(id, name) VALUES(:id, :name)"
|
||||
insert-pokemon-order-arg: "INSERT INTO Pokemons(id, name) VALUES(?, ?)"
|
||||
# Pokemon mapper uses reverse order of indexed arguments
|
||||
insert-pokemon-order-arg-rev: "INSERT INTO Pokemons(name, id) VALUES(?, ?)"
|
||||
# test DML update
|
||||
select-pokemon-by-id: "SELECT id, name FROM Pokemons WHERE id=?"
|
||||
update-pokemon-named-arg: "UPDATE Pokemons SET name=:name WHERE id=:id"
|
||||
update-pokemon-order-arg: "UPDATE Pokemons SET name=? WHERE id=?"
|
||||
# test DML delete
|
||||
delete-pokemon-named-arg: "DELETE FROM Pokemons WHERE id=:id"
|
||||
delete-pokemon-order-arg: "DELETE FROM Pokemons WHERE id=?"
|
||||
# Pokemon mapper uses full list of attributes
|
||||
delete-pokemon-full-named-arg: "DELETE FROM Pokemons WHERE name=:name AND id=:id"
|
||||
delete-pokemon-full-order-arg: "DELETE FROM Pokemons WHERE name=? AND id=?"
|
||||
# test DbStatementQuery methods
|
||||
select-pokemons-idrng-named-arg: "SELECT id, name FROM Pokemons WHERE id > :idmin AND id < :idmax"
|
||||
select-pokemons-idrng-order-arg: "SELECT id, name FROM Pokemons WHERE id > ? AND id < ?"
|
||||
# Test query with both named and ordered parameters (shall cause an exception)
|
||||
select-pokemons-error-arg: "SELECT id, name FROM Pokemons WHERE id > :id AND name = ?"
|
||||
|
||||
# Tests configuration
|
||||
test:
|
||||
# Whether database supports ping statement as DML (default value is true)
|
||||
#ping-dml: true
|
||||
@@ -21,16 +21,18 @@ server:
|
||||
db:
|
||||
source: jdbc
|
||||
connection:
|
||||
url: jdbc:mysql://${mysql.host}:${mysql.port}/${mysql.database}?useSSL=false&allowPublicKeyRetrieval=true
|
||||
username: ${mysql.user}
|
||||
password: ${mysql.password}
|
||||
url: jdbc:postgresql://${db.host}:${db.port}/${db.database}
|
||||
username: ${db.user}
|
||||
password: ${db.password}
|
||||
statements:
|
||||
# required ping statement
|
||||
ping: "DO 0"
|
||||
ping: "SELECT 0"
|
||||
# custom query ping statement
|
||||
ping-query: "SELECT 0"
|
||||
# database schema initialization statements
|
||||
create-types: "CREATE TABLE Types (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)"
|
||||
create-pokemons: "CREATE TABLE Pokemons (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(64) NOT NULL)"
|
||||
create-poketypes: "CREATE TABLE PokemonTypes (id_pokemon INTEGER NOT NULL REFERENCES Pokemon(id), id_type INTEGER NOT NULL REFERENCES Type(id))"
|
||||
create-poketypes: "CREATE TABLE PokemonTypes (id_pokemon INTEGER NOT NULL REFERENCES Pokemons(id), id_type INTEGER NOT NULL REFERENCES Types(id))"
|
||||
# database schema cleanup statements
|
||||
drop-types: "DROP TABLE Types"
|
||||
drop-pokemons: "DROP TABLE Pokemons"
|
||||
@@ -70,3 +72,8 @@ db:
|
||||
select-pokemons-idrng-order-arg: "SELECT id, name FROM Pokemons WHERE id > ? AND id < ?"
|
||||
# Test query with both named and ordered parameters (shall cause an exception)
|
||||
select-pokemons-error-arg: "SELECT id, name FROM Pokemons WHERE id > :id AND name = ?"
|
||||
|
||||
# Tests configuration
|
||||
test:
|
||||
# Whether database supports ping statement as DML (default value is true)
|
||||
ping-dml: false
|
||||
Reference in New Issue
Block a user