diff --git a/README.md b/README.md
index 3e5c211..35a088d 100644
--- a/README.md
+++ b/README.md
@@ -123,6 +123,12 @@ The file tnsnames.ora must contain valid TNS entries.
-exclude=pckg_list - Comma-separated object list to exclude from the coverage report.
Format: [schema.]package[,[schema.]package ...].
See coverage reporting options in framework documentation.
+
+-q - Does not output the informational messages normally printed to console.
+ Default: false
+
+-d - Outputs a load of debug information to console
+ Default: false
```
Parameters -f, -o, -s are correlated. That is parameters -o and -s are controlling outputs for reporter specified by the preceding -f parameter.
diff --git a/pom.xml b/pom.xml
index edf96a2..cb09913 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,36 +20,42 @@
-
- org.utplsql
- java-api
- 3.1.2
- compile
-
-
- com.oracle.jdbc
- ucp
-
-
-
-
- com.beust
- jcommander
- 1.72
- compile
-
-
- com.zaxxer
- HikariCP
- 2.7.2
- compile
-
- org.slf4j
- slf4j-nop
- 1.7.25
+ org.utplsql
+ java-api
+ 3.1.3-SNAPSHOT
compile
+
+
+ com.oracle.jdbc
+ ucp
+
+
+
+ com.beust
+ jcommander
+ 1.72
+ compile
+
+
+ com.zaxxer
+ HikariCP
+ 2.7.2
+ compile
+
+
+ javax.xml.bind
+ jaxb-api
+ 2.3.0
+
+
+ ch.qos.logback
+ logback-classic
+ 1.2.3
+
+
+
org.junit.jupiter
junit-jupiter-api
@@ -62,11 +68,7 @@
${junit.jupiter.version}
test
-
- javax.xml.bind
- jaxb-api
- 2.3.0
-
+
diff --git a/src/main/java/org/utplsql/cli/Cli.java b/src/main/java/org/utplsql/cli/Cli.java
index a2e9202..f82d80c 100644
--- a/src/main/java/org/utplsql/cli/Cli.java
+++ b/src/main/java/org/utplsql/cli/Cli.java
@@ -18,6 +18,8 @@ public static void main(String[] args) {
}
static int runWithExitCode( String[] args ) {
+
+ LoggerConfiguration.configure(LoggerConfiguration.ConfigLevel.NONE);
LocaleInitializer.initLocale();
JCommander jc = new JCommander();
diff --git a/src/main/java/org/utplsql/cli/LoggerConfiguration.java b/src/main/java/org/utplsql/cli/LoggerConfiguration.java
new file mode 100644
index 0000000..a10d8e6
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/LoggerConfiguration.java
@@ -0,0 +1,79 @@
+package org.utplsql.cli;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.ConsoleAppender;
+import com.zaxxer.hikari.HikariDataSource;
+import org.slf4j.LoggerFactory;
+
+class LoggerConfiguration {
+
+ public enum ConfigLevel {
+ BASIC, NONE, DEBUG
+ }
+
+ private LoggerConfiguration() {
+ throw new UnsupportedOperationException();
+ }
+
+ static void configure(ConfigLevel level) {
+ switch ( level ) {
+ case BASIC:
+ configureInfo();
+ break;
+ case NONE:
+ configureSilent();
+ break;
+ case DEBUG:
+ configureDebug();
+ break;
+ }
+ }
+
+ private static void configureSilent() {
+ setRootLoggerLevel(Level.OFF);
+ }
+
+ private static void configureInfo() {
+ setRootLoggerLevel(Level.INFO);
+ muteHikariLogger();
+ setSingleConsoleAppenderWithLayout("%msg%n");
+ }
+
+ private static void configureDebug() {
+ setRootLoggerLevel(Level.DEBUG);
+ setSingleConsoleAppenderWithLayout("%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n");
+ }
+
+ private static void setRootLoggerLevel( Level level ) {
+ Logger root = (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+ root.setLevel(level);
+ }
+
+ private static void muteHikariLogger() {
+ ((Logger) LoggerFactory.getLogger(HikariDataSource.class)).setLevel(Level.OFF);
+ }
+
+ private static void setSingleConsoleAppenderWithLayout( String patternLayout ) {
+ Logger logger = (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+ LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
+
+ PatternLayoutEncoder ple = new PatternLayoutEncoder();
+ ple.setPattern(patternLayout);
+
+ ple.setContext(lc);
+ ple.start();
+
+ ConsoleAppender consoleAppender = new ConsoleAppender<>();
+ consoleAppender.setEncoder(ple);
+ consoleAppender.setContext(lc);
+ consoleAppender.start();
+
+ logger.detachAndStopAllAppenders();
+ logger.setAdditive(false);
+ logger.addAppender(consoleAppender);
+ }
+}
diff --git a/src/main/java/org/utplsql/cli/ReportersCommand.java b/src/main/java/org/utplsql/cli/ReportersCommand.java
index 6d297a4..0c3560a 100644
--- a/src/main/java/org/utplsql/cli/ReportersCommand.java
+++ b/src/main/java/org/utplsql/cli/ReportersCommand.java
@@ -47,6 +47,7 @@ public int run() {
}
catch ( DatabaseNotCompatibleException | UtPLSQLNotInstalledException | DatabaseConnectionFailed | IllegalArgumentException e ) {
System.out.println(e.getMessage());
+ return 1;
}
catch (Exception e) {
e.printStackTrace();
diff --git a/src/main/java/org/utplsql/cli/RunCommand.java b/src/main/java/org/utplsql/cli/RunCommand.java
index 01ecdbd..4142f9a 100644
--- a/src/main/java/org/utplsql/cli/RunCommand.java
+++ b/src/main/java/org/utplsql/cli/RunCommand.java
@@ -2,17 +2,18 @@
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
-import org.utplsql.api.FileMapperOptions;
-import org.utplsql.api.KeyValuePair;
-import org.utplsql.api.TestRunner;
-import org.utplsql.api.Version;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.utplsql.api.*;
import org.utplsql.api.compatibility.CompatibilityProxy;
+import org.utplsql.api.db.DefaultDatabaseInformation;
import org.utplsql.api.exception.DatabaseNotCompatibleException;
import org.utplsql.api.exception.SomeTestsFailedException;
import org.utplsql.api.exception.UtPLSQLNotInstalledException;
import org.utplsql.api.reporter.Reporter;
import org.utplsql.api.reporter.ReporterFactory;
import org.utplsql.cli.exception.DatabaseConnectionFailed;
+import org.utplsql.cli.log.StringBlockFormatter;
import javax.sql.DataSource;
import java.io.File;
@@ -34,6 +35,8 @@
@Parameters(separators = "=", commandDescription = "run tests")
public class RunCommand implements ICommand {
+ private static final Logger logger = LoggerFactory.getLogger(RunCommand.class);
+
@Parameter(
required = true,
converter = ConnectionInfo.ConnectionStringConverter.class,
@@ -99,6 +102,15 @@ public class RunCommand implements ICommand {
)
private String excludeObjects = null;
+ @Parameter(
+ names = {"-q", "--quiet"},
+ description = "Does not output the informational messages normally printed to console")
+ private boolean logSilent = false;
+
+ @Parameter(
+ names = {"-d", "--debug"},
+ description = "Outputs a load of debug information to console")
+ private boolean logDebug = false;
private CompatibilityProxy compatibilityProxy;
private ReporterFactory reporterFactory;
@@ -112,7 +124,22 @@ public List getTestPaths() {
return testPaths;
}
+ void init() {
+
+ LoggerConfiguration.ConfigLevel level = LoggerConfiguration.ConfigLevel.BASIC;
+ if ( logSilent ) {
+ level = LoggerConfiguration.ConfigLevel.NONE;
+ }
+ else if ( logDebug ) {
+ level = LoggerConfiguration.ConfigLevel.DEBUG;
+ }
+
+ LoggerConfiguration.configure(level);
+ }
+
public int run() {
+ init();
+ outputMainInformation();
try {
@@ -148,25 +175,8 @@ public int run() {
final DataSource dataSource = DataSourceProvider.getDataSource(getConnectionInfo(), getReporterManager().getNumberOfReporters() + 1);
- // Do the reporters initialization, so we can use the id to run and gather results.
- try (Connection conn = dataSource.getConnection()) {
-
- // Check if orai18n exists if database version is 11g
- RunCommandChecker.checkOracleI18nExists(conn);
-
- // First of all do a compatibility check and fail-fast
- compatibilityProxy = checkFrameworkCompatibility(conn);
- reporterFactory = ReporterFactoryProvider.createReporterFactory(compatibilityProxy);
-
- reporterList = getReporterManager().initReporters(conn, reporterFactory, compatibilityProxy);
-
- } catch (SQLException e) {
- if (e.getErrorCode() == 1017 || e.getErrorCode() == 12514) {
- throw new DatabaseConnectionFailed(e);
- } else {
- throw e;
- }
- }
+ initDatabase(dataSource);
+ reporterList = initReporters(dataSource);
// Output a message if --failureExitCode is set but database framework is not capable of
String msg = RunCommandChecker.getCheckFailOnErrorMessage(failureExitCode, compatibilityProxy.getDatabaseVersion());
@@ -190,6 +200,8 @@ public int run() {
.includeObjects(finalIncludeObjectsList)
.excludeObjects(finalExcludeObjectsList);
+ logger.info("Running tests now.");
+ logger.info("--------------------------------------");
testRunner.run(conn);
} catch (SomeTestsFailedException e) {
returnCode[0] = this.failureExitCode;
@@ -205,6 +217,10 @@ public int run() {
executorService.shutdown();
executorService.awaitTermination(60, TimeUnit.MINUTES);
+
+ logger.info("--------------------------------------");
+ logger.info("All tests done.");
+
return returnCode[0];
}
catch ( DatabaseNotCompatibleException | UtPLSQLNotInstalledException | DatabaseConnectionFailed e ) {
@@ -221,6 +237,49 @@ public String getCommand() {
}
+ private void outputMainInformation() {
+
+ StringBlockFormatter formatter = new StringBlockFormatter("utPLCSL cli");
+ formatter.appendLine(CliVersionInfo.getInfo());
+ formatter.appendLine(JavaApiVersionInfo.getInfo());
+ formatter.appendLine("Java-Version: " + System.getProperty("java.version"));
+ formatter.appendLine("ORACLE_HOME: " + EnvironmentVariableUtil.getEnvValue("ORACLE_HOME"));
+ formatter.appendLine("NLS_LANG: " + EnvironmentVariableUtil.getEnvValue("NLS_LANG"));
+ formatter.appendLine("");
+ formatter.appendLine("Thanks for testing!");
+
+ logger.info(formatter.toString());
+ logger.info("");
+ }
+
+ private void initDatabase(DataSource dataSource) throws SQLException {
+ try (Connection conn = dataSource.getConnection()) {
+
+ // Check if orai18n exists if database version is 11g
+ RunCommandChecker.checkOracleI18nExists(conn);
+
+ // First of all do a compatibility check and fail-fast
+ compatibilityProxy = checkFrameworkCompatibility(conn);
+
+ logger.info("Successfully connected to database. UtPLSQL core: {}", compatibilityProxy.getDatabaseVersion());
+ logger.info("Oracle-Version: {}", new DefaultDatabaseInformation().getOracleVersion(conn));
+ }
+ catch (SQLException e) {
+ if (e.getErrorCode() == 1017 || e.getErrorCode() == 12514) {
+ throw new DatabaseConnectionFailed(e);
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ private List initReporters(DataSource dataSource) throws SQLException {
+ try (Connection conn = dataSource.getConnection()) {
+ reporterFactory = ReporterFactoryProvider.createReporterFactory(compatibilityProxy);
+ return getReporterManager().initReporters(conn, reporterFactory, compatibilityProxy);
+ }
+ }
+
/** Returns FileMapperOptions for the first item of a given param list in a baseDir
*
* @param pathParams
diff --git a/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java b/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java
index f30cd91..a0bc3ab 100644
--- a/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java
+++ b/src/main/java/org/utplsql/cli/datasource/TestedDataSourceProvider.java
@@ -1,6 +1,8 @@
package org.utplsql.cli.datasource;
import com.zaxxer.hikari.HikariDataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.utplsql.api.EnvironmentVariableUtil;
import org.utplsql.cli.ConnectionConfig;
import org.utplsql.cli.exception.DatabaseConnectionFailed;
@@ -19,6 +21,7 @@ interface ConnectStringPossibility {
String getMaskedConnectString(ConnectionConfig config);
}
+ private static final Logger logger = LoggerFactory.getLogger(TestedDataSourceProvider.class);
private final ConnectionConfig config;
private List possibilities = new ArrayList<>();
@@ -43,9 +46,14 @@ private void setThickOrThinJdbcUrl(HikariDataSource ds ) throws SQLException
{
List errors = new ArrayList<>();
Throwable lastException = null;
+
+ ds.setUsername(config.getUser());
+ ds.setPassword(config.getPassword());
+
for (ConnectStringPossibility possibility : possibilities) {
ds.setJdbcUrl(possibility.getConnectString(config));
try (Connection con = ds.getConnection()) {
+ logger.info("Use connectstring {}", possibility.getMaskedConnectString(config));
return;
} catch (UnsatisfiedLinkError | Exception e) {
errors.add(possibility.getMaskedConnectString(config) + ": " + e.getMessage());
@@ -78,6 +86,7 @@ private void setInitSqlFrom_NLS_LANG(HikariDataSource ds ) {
sb.append(String.format("EXECUTE IMMEDIATE q'[%s]';\n", command));
sb.append("END;");
+ logger.debug("NLS settings: {}", sb.toString());
ds.setConnectionInitSql(sb.toString());
}
}
@@ -87,7 +96,7 @@ private void setInitSqlFrom_NLS_LANG(HikariDataSource ds ) {
private static class ThickConnectStringPossibility implements ConnectStringPossibility {
@Override
public String getConnectString(ConnectionConfig config) {
- return "jdbc:oracle:oci8:" + config.getConnectString();
+ return "jdbc:oracle:oci8:@" + config.getConnect();
}
@Override
@@ -99,7 +108,7 @@ public String getMaskedConnectString(ConnectionConfig config) {
private static class ThinConnectStringPossibility implements ConnectStringPossibility {
@Override
public String getConnectString(ConnectionConfig config) {
- return "jdbc:oracle:thin:" + config.getConnectString();
+ return "jdbc:oracle:thin:@" + config.getConnect();
}
@Override
diff --git a/src/main/java/org/utplsql/cli/log/StringBlockFormatter.java b/src/main/java/org/utplsql/cli/log/StringBlockFormatter.java
new file mode 100644
index 0000000..d73656f
--- /dev/null
+++ b/src/main/java/org/utplsql/cli/log/StringBlockFormatter.java
@@ -0,0 +1,81 @@
+package org.utplsql.cli.log;
+
+public class StringBlockFormatter {
+
+ private String headline;
+ private StringBuilder content = new StringBuilder();
+
+ public StringBlockFormatter() {}
+
+ public StringBlockFormatter(String headline) {
+ setHeadline(headline);
+ }
+
+ public void setHeadline(String headline) {
+ this.headline = headline;
+ }
+
+ public String getHeadline() {
+ return headline;
+ }
+
+ public void append( CharSequence seq ) {
+ content.append(seq);
+ }
+
+ public void appendLine( CharSequence seq ) {
+ content.append(seq).append("\n");
+ }
+
+ private int getMaxLength( String[] lines ) {
+ int len = 0;
+ for ( String line : lines ) {
+ if (line.length() > len)
+ len = line.length();
+ }
+
+ if ( headline.length() > (len+6))
+ len = headline.length();
+
+ return len;
+ }
+
+ public static String getEncapsulatedLine( String line, int maxLength ) {
+ return String.format("# %-" + maxLength + "s #", line);
+ }
+
+ public static String getEncapsulatedHeadline( String headline, int maxLength ) {
+ String content = new String(new char[maxLength+8]).replace("\0", "#");
+ if ( headline == null || headline.isEmpty() )
+ return content;
+
+ headline = " " + headline + " ";
+ int start = (int)Math.floor(
+ (float)content.length()/2f
+ -(float)headline.length()/2f
+ );
+ int end = start + headline.length();
+
+ return content.substring(0, start)
+ + headline
+ + content.substring(end);
+ }
+
+ public String toString() {
+
+ String[] lines = content.toString().split("\n");
+ int maxLen = getMaxLength(lines);
+
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(getEncapsulatedHeadline(headline, maxLen)).append("\n");
+ sb.append(getEncapsulatedLine("", maxLen)).append("\n");
+ for ( String line : lines ) {
+ sb.append(getEncapsulatedLine(line, maxLen)).append("\n");
+ }
+ sb.append(getEncapsulatedLine("", maxLen)).append("\n");
+ sb.append(getEncapsulatedHeadline("", maxLen));
+
+ return sb.toString();
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/RunCommandConfigLevelTest.java b/src/test/java/org/utplsql/cli/RunCommandConfigLevelTest.java
new file mode 100644
index 0000000..411a0e3
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/RunCommandConfigLevelTest.java
@@ -0,0 +1,39 @@
+package org.utplsql.cli;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import org.junit.jupiter.api.Test;
+import org.slf4j.LoggerFactory;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class RunCommandConfigLevelTest {
+
+ private Logger getRootLogger() {
+ return (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+ }
+
+ @Test
+ void defaultIsInfo() {
+ TestHelper.createRunCommand(TestHelper.getConnectionString())
+ .init();
+
+ assertEquals(Level.INFO, getRootLogger().getLevel());
+ }
+
+ @Test
+ void silentModeSetsLoggerToOff() {
+ TestHelper.createRunCommand(TestHelper.getConnectionString(), "-q")
+ .init();
+
+ assertEquals(Level.OFF, getRootLogger().getLevel());
+ }
+
+ @Test
+ void debugModeSetsLoggerToDebug() {
+ TestHelper.createRunCommand(TestHelper.getConnectionString(), "-d")
+ .init();
+
+ assertEquals(Level.DEBUG, getRootLogger().getLevel());
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/RunCommandIT.java b/src/test/java/org/utplsql/cli/RunCommandIT.java
index f03b4d2..fbf35e5 100644
--- a/src/test/java/org/utplsql/cli/RunCommandIT.java
+++ b/src/test/java/org/utplsql/cli/RunCommandIT.java
@@ -29,6 +29,17 @@ public void run_Default() throws Exception {
else
assertEquals(0, result);
}
+
+ @Test
+ public void run_Debug() throws Exception {
+
+ int result = TestHelper.runApp("run",
+ TestHelper.getConnectionString(),
+ "--debug");
+
+ assertEquals(1, result);
+ }
+
@Test
public void run_MultipleReporters() throws Exception {
diff --git a/src/test/java/org/utplsql/cli/StringBlockFormatterTest.java b/src/test/java/org/utplsql/cli/StringBlockFormatterTest.java
new file mode 100644
index 0000000..62fc5f6
--- /dev/null
+++ b/src/test/java/org/utplsql/cli/StringBlockFormatterTest.java
@@ -0,0 +1,55 @@
+package org.utplsql.cli;
+
+import org.junit.jupiter.api.Test;
+import org.utplsql.cli.log.StringBlockFormatter;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class StringBlockFormatterTest {
+
+ @Test
+ void getBlockFormattedString() {
+
+ String expected =
+ "#### Headline ####\n" +
+ "# #\n" +
+ "# My value 1 #\n" +
+ "# My val 2 #\n" +
+ "# #\n" +
+ "##################";
+
+ StringBlockFormatter formatter = new StringBlockFormatter("Headline");
+ formatter.appendLine("My value 1");
+ formatter.appendLine("My val 2");
+
+ assertEquals( expected, formatter.toString() );
+ }
+
+ @Test
+ void getEncapsulatedLine() {
+
+ String line = StringBlockFormatter.getEncapsulatedLine("val 1", 20);
+
+ assertEquals("# val 1 #", line);
+ }
+
+ @Test
+ void getEncapsulatedHeadline() {
+
+ assertEquals("######### headline #########",
+ StringBlockFormatter.getEncapsulatedHeadline("headline", 20));
+ assertEquals("######### headline ##########",
+ StringBlockFormatter.getEncapsulatedHeadline("headline", 21));
+ assertEquals("######### headline1 #########",
+ StringBlockFormatter.getEncapsulatedHeadline("headline1", 21));
+ assertEquals("######## headline1 #########",
+ StringBlockFormatter.getEncapsulatedHeadline("headline1", 20));
+ }
+
+ @Test
+ void getEmptyEncapsulatedHeadline() {
+
+ assertEquals("##################",
+ StringBlockFormatter.getEncapsulatedHeadline("", 10));
+ }
+}
diff --git a/src/test/java/org/utplsql/cli/TestRunCommandChecker.java b/src/test/java/org/utplsql/cli/TestRunCommandChecker.java
index fcf2d21..0b1a651 100644
--- a/src/test/java/org/utplsql/cli/TestRunCommandChecker.java
+++ b/src/test/java/org/utplsql/cli/TestRunCommandChecker.java
@@ -15,7 +15,7 @@ public void getCheckFailOnErrorMessage()
assertNotNull(RunCommandChecker.getCheckFailOnErrorMessage(2, new Version("3.0.0")));
assertNotNull(RunCommandChecker.getCheckFailOnErrorMessage(2, new Version("3.0.1")));
assertNotNull(RunCommandChecker.getCheckFailOnErrorMessage(2, new Version("3.0.2")));
- assertNull(RunCommandChecker.getCheckFailOnErrorMessage(2, new Version("3.0.3")));
+ assertNull(RunCommandChecker.getCheckFailOnErrorMessage(2, new Version("3.0.3.1266")));
assertNull(RunCommandChecker.getCheckFailOnErrorMessage(2, new Version("3.0.4")));
}
}