/*
* #%L
* P6Spy
* %%
* Copyright (C) 2013 P6Spy
* %%
* 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.
* #L%
*/
package com.p6spy.engine.spy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.p6spy.engine.common.P6Util;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import com.p6spy.engine.logging.Category;
import com.p6spy.engine.logging.P6LogOptions;
import com.p6spy.engine.spy.appender.MultiLineFormat;
import com.p6spy.engine.spy.appender.P6TestLogger;
import com.p6spy.engine.spy.appender.SingleLineFormat;
import com.p6spy.engine.spy.appender.StdoutLogger;
import com.p6spy.engine.spy.option.SystemProperties;
import com.p6spy.engine.test.P6TestFramework;
@RunWith(Parameterized.class)
public class P6TestCommon extends P6TestFramework {
Statement statement = null;
public P6TestCommon(String db) throws SQLException, IOException {
super(db);
}
@Before
public void setUpCommon() throws SQLException {
statement = connection.createStatement();
}
@Test
public void testIncludeExclude() throws SQLException {
final String query = "select 'x' from customers";
// include null && exclude null => logged
{
super.clearLogEntries();
assertNull(P6LogOptions.getActiveInstance().getExcludeList());
assertNull(P6LogOptions.getActiveInstance().getIncludeList());
statement.executeQuery(query);
assertEquals(1, super.getLogEntriesCount());
assertTrue(super.getLastLogEntry().contains(query));
}
// include empty && exclude empty => logged
{
super.clearLogEntries();
// adding and clearing afterwards causes nulled sets
P6LogOptions.getActiveInstance().setInclude("non_existing_table");
P6LogOptions.getActiveInstance().setInclude("");
P6LogOptions.getActiveInstance().setExclude("non_existing_table");
P6LogOptions.getActiveInstance().setExclude("");
assertNull(P6LogOptions.getActiveInstance().getIncludeList());
assertNull(P6LogOptions.getActiveInstance().getExcludeList());
statement.executeQuery(query);
assertEquals(1, super.getLogEntriesCount());
assertTrue(super.getLastLogEntry().contains(query));
}
// table is excluded => NOT logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setExclude(
"non_existing_table1,customers,non_existing_table2,non_existing_table3");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setExclude("");
assertEquals(0, super.getLogEntriesCount());
}
// table is included => logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setInclude("customers");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setInclude("");
assertEquals(1, super.getLogEntriesCount());
assertTrue(super.getLastLogEntry().contains(query));
}
// table is NOT included (but include is non-empty) => NOT logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setInclude("non_existing_table");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setInclude("");
assertEquals(0, super.getLogEntriesCount());
}
// excluded - case insensitive => not logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setExclude("SELECT");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setExclude("");
assertEquals(0, super.getLogEntriesCount());
}
// included - case insensitive => logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setInclude("SELECT");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setInclude("");
assertEquals(1, super.getLogEntriesCount());
}
final String queryMultiline = "select * \nfrom customers";
// excluded - multiline => not logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setExclude("customers");
statement.executeQuery(queryMultiline);
P6LogOptions.getActiveInstance().setExclude("");
assertEquals(0, super.getLogEntriesCount());
}
// included - multiline => logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setInclude("customers");
statement.executeQuery(queryMultiline);
P6LogOptions.getActiveInstance().setInclude("");
assertEquals(1, super.getLogEntriesCount());
}
}
@Test
public void testIncludeOtherTableShouldLogResultSet() throws SQLException {
final String query = "select 'x' from customers";
super.clearLogEntries();
P6SpyOptions.getActiveInstance().setStackTrace("true");
// other table is included => resultset is still logged
P6LogOptions.getActiveInstance().setInclude("non_existing_table1");
P6LogOptions.getActiveInstance().setExcludecategories("info,debug,batch");
ResultSet rs = statement.executeQuery(query);
while (rs.next()) {
@SuppressWarnings("unused")
String value = rs.getString(1);
}
P6LogOptions.getActiveInstance().setInclude("");
assertEquals(0, super.getLogEntriesCount());
}
@Test
public void testExcludeThisTableShouldLogResultSet() throws SQLException {
super.clearLogEntries();
final String query = "select 'x' from customers";
// table is excluded => resultset is still logged
P6LogOptions.getActiveInstance().setExclude("customers");
P6LogOptions.getActiveInstance().setExcludecategories("info,debug,batch");
ResultSet rs = statement.executeQuery(query);
if (rs.next()) {
@SuppressWarnings("unused")
String value = rs.getString(1);
}
P6LogOptions.getActiveInstance().setExclude("");
assertEquals(0, super.getLogEntriesCount());
}
@Test
public void testIncludeExcludeRegexp() throws SQLException {
final String query = "select 'y' from customers";
// table is excluded (matches regexp) => NOT logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setExclude("[a-z]ustomers");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setExclude("");
assertEquals(0, super.getLogEntriesCount());
}
// table is NOT excluded (doesn't match regexp) => logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setExclude("[0-9]tmt_test");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setExclude("");
assertEquals(1, super.getLogEntriesCount());
assertTrue(super.getLastLogEntry().contains(query));
}
// backslashes (have to be doubled)
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setExclude("from\\scustomer");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setExclude("");
assertEquals(0, super.getLogEntriesCount());
}
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setInclude("from\\scustomer");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setInclude("");
assertEquals(1, super.getLogEntriesCount());
assertTrue(super.getLastLogEntry().contains(query));
}
}
@Test
public void testSqlExpressionPattern() throws SQLException {
final String query = "select 'y' from customers";
// sql expression NOT matched => NOT logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setSQLExpression("^select[ ]'x'.*$");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().unSetSQLExpression();
assertEquals(0, super.getLogEntriesCount());
}
// sql expression matched => NOT logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setSQLExpression("^select[ ]'y'.*$");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().unSetSQLExpression();
assertEquals(1, super.getLogEntriesCount());
assertTrue(super.getLastLogEntry().contains(query));
}
// multiline + case insensitive + dotall matched => logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setSQLExpression("(?mis)^.*FROM.*$");
final String queryMultiline = "select * \nfrom customers";
statement.executeQuery(queryMultiline);
P6LogOptions.getActiveInstance().unSetSQLExpression();
assertEquals(1, super.getLogEntriesCount());
assertTrue(super.getLastLogEntry().contains(P6Util.singleLine(queryMultiline)));
}
// backslashes (have to be doubled)
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setSQLExpression("^.*from\\scustomer.*$");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().unSetSQLExpression();
assertEquals(1, super.getLogEntriesCount());
assertTrue(super.getLastLogEntry().contains(query));
}
}
@Test
public void testIncludeExcludeWithSqlExpressionPattern() throws SQLException {
final String query = "select 'x' from customers";
// include/exclude passes AND sqlexpression does NOT pass => NOT logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setInclude("customers");
P6LogOptions.getActiveInstance().setExclude("foo");
P6LogOptions.getActiveInstance().setSQLExpression("^.*bar\\s.*$");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setInclude("");
P6LogOptions.getActiveInstance().setExclude("");
P6LogOptions.getActiveInstance().unSetSQLExpression();
assertEquals(0, super.getLogEntriesCount());
}
// include/exclude does NOT pass AND sqlexpression passes => NOT logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setExclude("customers");
P6LogOptions.getActiveInstance().setSQLExpression("^.*from\\s.*$");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setExclude("");
P6LogOptions.getActiveInstance().unSetSQLExpression();
assertEquals(0, super.getLogEntriesCount());
}
// include/exclude passes AND sqlexpression passes => logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setInclude("customers");
P6LogOptions.getActiveInstance().setExclude("foo");
P6LogOptions.getActiveInstance().setSQLExpression("^.*from\\s.*$");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setInclude("");
P6LogOptions.getActiveInstance().setExclude("");
P6LogOptions.getActiveInstance().unSetSQLExpression();
assertEquals(1, super.getLogEntriesCount());
assertTrue(super.getLastLogEntry().contains(query));
}
// include/exclude NOT SET AND sqlexpression passes => logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setSQLExpression("^.*from\\s.*$");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().unSetSQLExpression();
assertEquals(1, super.getLogEntriesCount());
assertTrue(super.getLastLogEntry().contains(query));
}
// include/exclude passes AND sqlexpression NOT SET => logged
{
super.clearLogEntries();
P6LogOptions.getActiveInstance().setInclude("customers");
P6LogOptions.getActiveInstance().setExclude("foo");
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setInclude("");
P6LogOptions.getActiveInstance().setExclude("");
assertEquals(1, super.getLogEntriesCount());
assertTrue(super.getLastLogEntry().contains(query));
}
// include/exclude NOT SET AND sqlexpression NOT SET => logged
{
super.clearLogEntries();
statement.executeQuery(query);
assertEquals(1, super.getLogEntriesCount());
assertTrue(super.getLastLogEntry().contains(query));
}
}
@Test
public void testCategories() throws Exception {
// we would like to see transactions in action here => prevent autocommit
connection.setAutoCommit(false);
// test rollback logging
super.clearLogEntries();
String query = "select 'y' from customers";
statement.executeQuery(query);
assertTrue(super.getLastLogEntry().contains(query));
statement.close(); // required for sqllite
connection.rollback();
assertTrue(super.getLastLogEntry().contains(Category.ROLLBACK.toString()));
statement = connection.createStatement();
// test commit logging
super.clearLogEntries();
query = "select 'y' from customers";
statement.executeQuery(query);
assertTrue(super.getLastLogEntry().contains(query));
connection.commit();
assertTrue(super.getLastLogEntry().contains(Category.COMMIT.toString()));
// test debug logging
super.clearLogEntries();
P6LogOptions.getActiveInstance().setExclude("customers");
P6LogOptions.getActiveInstance().setExcludecategories("");
query = "select 'y' from customers";
statement.executeQuery(query);
P6LogOptions.getActiveInstance().setExclude("");
P6LogOptions.getActiveInstance().setExcludecategories("debug");
assertTrue(super.getLastLogEntry().contains("intentionally"));
// test result + resultset logging
testResultAndResultSetCategory(true, true);
testResultAndResultSetCategory(true, false);
testResultAndResultSetCategory(false, true);
testResultAndResultSetCategory(false, false);
// set back, otherwise we have problems in PostgresSQL, statement exec
// waits for commit
connection.setAutoCommit(true);
}
private void testResultAndResultSetCategory(final boolean resultCategoryNotExcluded,
final boolean resultsetCategoryNotExcluded)
throws SQLException {
final String query = "select id, name from customers where id in (1,2)";
// debug would corrupt count checks here
final StringBuilder sb = new StringBuilder(Category.DEBUG.toString());
if (!resultCategoryNotExcluded) {
sb.append(",").append(Category.RESULT.toString());
}
if (!resultsetCategoryNotExcluded) {
sb.append(",").append(Category.RESULTSET.toString());
}
P6LogOptions.getActiveInstance().setExcludecategories(sb.toString());
final ResultSet resultSet = statement.executeQuery(query);
super.clearLogEntries();
while (resultSet.next()) {
String col1 = resultSet.getString("name");
assertTrue(col1.startsWith("david") || col1.startsWith("mary"));
}
int resultCount = 0;
int resultSetCount = 0;
for (String logMessage : getLogEntries()) {
if (logMessage.contains(Category.RESULT.toString()) && !logMessage.contains(Category.RESULTSET.toString())) {
resultCount++;
} else {
resultSetCount++;
}
}
assertEquals("incorrect number of log messages", resultCategoryNotExcluded ? 2 : 0, resultCount);
assertEquals("incorrect number of log messages", resultsetCategoryNotExcluded ? 2 : 0, resultSetCount);
resultSet.close();
// reset back to original setup
// P6LogOptions.getActiveInstance().setExcludecategories("resultset,result");
if (!resultCategoryNotExcluded && !resultsetCategoryNotExcluded) {
assertEquals(
"if \"result\" \"resultset\" are in excludecategories they should NOT be logged", 0,
super.getLogEntriesCount());
} else {
assertNotEquals(
"if \"result\" \"resultset\" are NOT in excludecategories they should be logged", 0,
super.getLogEntriesCount());
}
}
@Test
public void testMessageFormatStrategies() throws Exception {
// SingleLineFormat case (by default)
{
String query = "select count(*) from customers";
statement.executeQuery(query);
assertFalse(super.getLastLogEntry().contains("\n"));
}
// MultiLineFormat case
{
P6SpyOptions.getActiveInstance().setLogMessageFormat(MultiLineFormat.class.getName());
String query = "select count(*) from customers";
statement.executeQuery(query);
assertTrue(super.getLastLogEntry().contains("\n"));
}
// reset to default line format strategy
P6SpyOptions.getActiveInstance().setLogMessageFormat(SingleLineFormat.class.getName());
}
@Test
public void testStacktrace() throws SQLException {
P6SpyOptions.getActiveInstance().setStackTrace("true");
// perform a query & make sure we get the stack trace
String query = "select 'y' from customers";
statement.executeQuery(query);
assertTrue(super.getLastLogEntry().contains(query));
assertTrue(super.getLastLogStackTrace().contains("Stack"));
// filter on stack trace that will not match
super.clearLastLogStackTrace();
P6SpyOptions.getActiveInstance().setStackTraceClass("com.dont.match");
query = "select 'a' from customers";
statement.executeQuery(query);
// this will actually match - just the stack trace wont fire
assertTrue(super.getLastLogEntry().contains(query));
assertNull(super.getLastLogStackTrace());
super.clearLastLogStackTrace();
P6SpyOptions.getActiveInstance().setStackTraceClass("com.p6spy");
query = "select 'b' from customers";
statement.executeQuery(query);
assertTrue(super.getLastLogEntry().contains(query));
assertTrue(super.getLastLogStackTrace().contains("Stack"));
}
@Test
public void testAppenderReconfigurationTakesPlaceImediatelly() throws Exception {
final String sql = "select count(*) from customers";
P6TestLogger oldAppenderRef = null;
// precondition - logging via P6TestLogger works OK
{
assertEquals(P6TestLogger.class.getName(), P6SpyOptions.getActiveInstance().getAppender());
super.clearLogEntries();
statement.executeQuery(sql);
oldAppenderRef = (P6TestLogger) P6SpyOptions.getActiveInstance().getAppenderInstance();
assertNotNull(oldAppenderRef.getLastEntry());
assertTrue(oldAppenderRef.getLastEntry().contains(sql));
}
super.clearLogEntries();
// let's log via StdoutLogger
P6SpyOptions.getActiveInstance().setAppender(StdoutLogger.class.getName());
assertEquals(StdoutLogger.class.getName(), P6SpyOptions.getActiveInstance().getAppender());
statement.executeQuery(sql);
// old appender should not be in use any more!
assertNull(oldAppenderRef.getLastEntry());
// cleanup stuff - go for the default logger
{
P6SpyOptions.getActiveInstance().setAppender(P6TestLogger.class.getName());
}
}
@Test
public void testDisableLogModule() throws SQLException {
P6SpyLoadableOptions o = P6SpyOptions.getActiveInstance();
assertNotNull(P6LogOptions.getActiveInstance());
clearLogEntries();
statement.executeQuery("select 'x' from customers");
// one log message should have been written - normal behavior
assertEquals("A log message should have been written", 1, getLogEntriesCount());
// hot module unload doesn't work
{
clearLogEntries();
o.setModulelist("");
statement.executeQuery("select 'x' from customers");
assertEquals("A log message should not have been written", 1, getLogEntriesCount());
}
// module unload with reload works
{
clearLogEntries();
System.setProperty(SystemProperties.P6SPY_PREFIX + P6SpyOptions.MODULELIST,
"");
o.reload();
statement.executeQuery("select 'x' from customers");
assertEquals("A log message should not have been written", 0, getLogEntriesCount());
System.clearProperty(SystemProperties.P6SPY_PREFIX + P6SpyOptions.MODULELIST);
}
}
}