[#1157] Add SQL / JDBC tracing capabilities in addition to logging - Added integration tests for using ExecuteListener with BatchSingle

This commit is contained in:
Lukas Eder 2012-02-24 14:06:27 +00:00
parent 80c1037759
commit fff0d5e529
5 changed files with 240 additions and 7 deletions

View File

@ -40,6 +40,8 @@ import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static org.jooq.impl.Factory.param;
import static org.jooq.impl.Factory.val;
import java.util.ArrayList;
@ -401,4 +403,215 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, D, T, U, I, IPK, T658, T725, T639
assertEquals(2, ctx.result().size());
}
}
@Test
public void testExecuteListenerOnBatchSingle() {
jOOQAbstractTest.reset = false;
Factory create = create(new Settings()
.withExecuteListeners(BatchSingleListener.class.getName()));
create.setData("Foo", "Bar");
create.setData("Bar", "Baz");
int[] result = create.batch(create().insertInto(TAuthor())
.set(TAuthor_ID(), param("id", Integer.class))
.set(TAuthor_LAST_NAME(), param("name", String.class)))
.bind(8, "Gamma")
.bind(9, "Helm")
.bind(10, "Johnson")
.execute();
assertEquals(3, result.length);
// Check correct order of listener method invocation
assertEquals(1, BatchSingleListener.start);
assertEquals(2, BatchSingleListener.renderStart);
assertEquals(3, BatchSingleListener.renderEnd);
assertEquals(4, BatchSingleListener.prepareStart);
assertEquals(5, BatchSingleListener.prepareEnd);
assertEquals(asList(6, 8, 10), BatchSingleListener.bindStart);
assertEquals(asList(7, 9, 11), BatchSingleListener.bindEnd);
assertEquals(12, BatchSingleListener.executeStart);
assertEquals(13, BatchSingleListener.executeEnd);
assertEquals(14, BatchSingleListener.end);
}
public static class BatchSingleListener implements ExecuteListener {
// A counter that is incremented in callback methods
private static int callbackCount = 0;
// Fields that are used to check whether callback methods were called
// in the expected order
public static int start;
public static int renderStart;
public static int renderEnd;
public static int prepareStart;
public static int prepareEnd;
public static List<Integer> bindStart = new ArrayList<Integer>();
public static List<Integer> bindEnd = new ArrayList<Integer>();
public static int executeStart;
public static int executeEnd;
public static int end;
public static Queue<Integer> ids = new LinkedList<Integer>(asList(1, 2));
@SuppressWarnings("serial")
private void checkBase(ExecuteContext ctx) {
assertNull(ctx.query());
assertNotNull(ctx.batchQueries());
assertTrue(ctx.batchQueries()[0].toString().contains("insert"));
assertEquals(1, ctx.batchSQL().length);
assertEquals("Bar", ctx.getData("Foo"));
assertEquals("Baz", ctx.getData("Bar"));
assertEquals(new HashMap<String, String>() {{
put("Foo", "Bar");
put("Bar", "Baz");
}}, ctx.getData());
assertNull(ctx.routine());
assertNull(ctx.resultSet());
assertNull(ctx.record());
assertNull(ctx.result());
assertEquals(ExecuteType.BATCH, ctx.type());
}
private void checkSQL(ExecuteContext ctx, boolean patched) {
assertTrue(ctx.batchSQL()[0].contains("insert"));
if (patched) {
assertTrue(ctx.batchSQL()[0].contains("values ("));
}
}
@SuppressWarnings("unused")
private void checkStatement(ExecuteContext ctx, boolean patched) {
assertNotNull(ctx.statement());
}
@Override
public void start(ExecuteContext ctx) {
start = ++callbackCount;
checkBase(ctx);
assertNull(ctx.batchSQL()[0]);
assertNull(ctx.sql());
assertNull(ctx.statement());
}
@Override
public void renderStart(ExecuteContext ctx) {
renderStart = ++callbackCount;
checkBase(ctx);
assertNull(ctx.batchSQL()[0]);
assertNull(ctx.sql());
assertNull(ctx.statement());
}
@Override
public void renderEnd(ExecuteContext ctx) {
renderEnd = ++callbackCount;
checkBase(ctx);
checkSQL(ctx, false);
assertNull(ctx.statement());
ctx.sql(ctx.sql().replaceFirst("values\\s+", "values "));
checkSQL(ctx, true);
}
@Override
public void prepareStart(ExecuteContext ctx) {
prepareStart = ++callbackCount;
checkBase(ctx);
checkSQL(ctx, true);
assertNull(ctx.statement());
}
@Override
public void prepareEnd(ExecuteContext ctx) {
prepareEnd = ++callbackCount;
checkBase(ctx);
checkSQL(ctx, true);
checkStatement(ctx, false);
// TODO Patch statement
checkStatement(ctx, true);
}
@Override
public void bindStart(ExecuteContext ctx) {
bindStart.add(++callbackCount);
checkBase(ctx);
checkSQL(ctx, true);
checkStatement(ctx, true);
}
@Override
public void bindEnd(ExecuteContext ctx) {
bindEnd.add(++callbackCount);
checkBase(ctx);
checkSQL(ctx, true);
checkStatement(ctx, true);
}
@Override
public void executeStart(ExecuteContext ctx) {
executeStart = ++callbackCount;
checkBase(ctx);
checkSQL(ctx, true);
checkStatement(ctx, true);
}
@Override
public void executeEnd(ExecuteContext ctx) {
executeEnd = ++callbackCount;
checkBase(ctx);
checkSQL(ctx, true);
checkStatement(ctx, true);
}
@Override
public void fetchStart(ExecuteContext ctx) {
fail();
}
@Override
public void resultStart(ExecuteContext ctx) {
fail();
}
@Override
public void recordStart(ExecuteContext ctx) {
fail();
}
@Override
public void recordEnd(ExecuteContext ctx) {
fail();
}
@Override
public void resultEnd(ExecuteContext ctx) {
fail();
}
@Override
public void fetchEnd(ExecuteContext ctx) {
fail();
}
@Override
public void end(ExecuteContext ctx) {
end = ++callbackCount;
checkBase(ctx);
checkSQL(ctx, true);
checkStatement(ctx, true);
}
}
}

View File

@ -382,9 +382,16 @@ public abstract class jOOQAbstractTest<
log.info("TEST STATISTICS");
log.info("---------------");
int total = 0;
for (ExecuteType type : ExecuteType.values()) {
Integer count = TestStatisticsListener.STATISTICS.get(type);
if (count != null) total += count;
log.info(type.name(), TestStatisticsListener.STATISTICS.get(type) + " executions");
}
log.info("---------------");
log.info("Total", total);
}
public final Connection getConnection() {
@ -1342,6 +1349,11 @@ public abstract class jOOQAbstractTest<
new ExecuteListenerTests(this).testExecuteListenerOnResultQuery();
}
@Test
public void testExecuteListenerOnBatchSingle() throws Exception {
new ExecuteListenerTests(this).testExecuteListenerOnBatchSingle();
}
@Test
public void testLoader() throws Exception {
new LoaderTests(this).testLoader();

View File

@ -65,12 +65,8 @@ public interface ExecuteContext extends Configuration {
/**
* The jOOQ {@link Query} that is being executed or <code>null</code> if the
* query is unknown or if there was no jOOQ <code>Query</code>
* <p>
* If {@link #batchQueries()} returns several <code>Query</code> objects,
* this will always return the currently rendered / prepared
* <code>Query</code>, or <code>null</code>, if no <code>Query</code> is
* currently being rendered / prepared
* query is unknown, if it is a batch query, or if there was no jOOQ
* <code>Query</code>
*
* @see #routine()
* @see #batchQueries()

View File

@ -70,7 +70,7 @@ class BatchSingle implements BatchBindStep {
public final int[] execute() {
Connection connection = create.getConnection();
ExecuteContext ctx = new DefaultExecuteContext(create, query);
ExecuteContext ctx = new DefaultExecuteContext(create, new Query[] { query });
ExecuteListener listener = new ExecuteListeners(ctx);
try {

View File

@ -114,12 +114,23 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont
@Override
public final ExecuteType type() {
// This can only be a routine
if (routine != null) {
return ExecuteType.ROUTINE;
}
// This can only be a BatchSingle execution
else if (batchQueries.length == 1 && query == null) {
return ExecuteType.BATCH;
}
// This can only be a BatchMultiple execution
else if (batchQueries.length > 1) {
return ExecuteType.BATCH;
}
// Any other type of query
else if (query != null) {
if (query instanceof ResultQuery) {
return ExecuteType.READ;
@ -136,6 +147,7 @@ class DefaultExecuteContext extends AbstractConfiguration implements ExecuteCont
}
}
// No query available
return ExecuteType.OTHER;
}