Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ public SqlBatchSizes findRecord(TestExecutionContext testExecutionContext) {

@Override
public void addQueryExecution(ExecutionInfo execInfo, List<QueryInfo> queries, int listenerIdentifier) {
if (isEmptyBatch(execInfo)) {
return;
}
for (QueryInfo query : queries) {
if ( previousStatementsAreBatched
&& isRequestTypeInsertOrUpdateOrDeleteType(query)
Expand All @@ -81,6 +84,12 @@ && isRequestTypeInsertOrUpdateOrDeleteType(query)
}
}

private boolean isEmptyBatch(ExecutionInfo execInfo) {
// An executeBatch() with nothing added sends no SQL, but its batch size is 0, like an unbatched execution.
// It is ignored, so that a recorded 0 batch size always means an unbatched execution
return execInfo.isBatch() && execInfo.getBatchSize() == 0;
}

private int[] createTableWithNewBatchSize(int batchSize) {
int newTableLength = differentBatchSizes.length + 1;
int[] newTable = new int[newTableLength];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,21 @@ private PerfIssue verifyThatInsertUpdateDeleteExecutionAreBatched(int[] measured
}

private int findNumberOfBatchSizeToCheck(int[] measuredBatchSizesAsArray) {
if(measuredBatchSizesAsArray.length == 1) {
return 1;
if(measuredBatchSizesAsArray.length <= 1) {
return measuredBatchSizesAsArray.length;
}
// The last batch can contain fewer statements, but a 0 batch size means that the last execution is not batched
if(lastExecutionIsNotBatched(measuredBatchSizesAsArray)) {
return measuredBatchSizesAsArray.length;
}
return measuredBatchSizesAsArray.length - 1;
}

private boolean lastExecutionIsNotBatched(int[] measuredBatchSizesAsArray) {
int lastBatchSize = measuredBatchSizesAsArray[measuredBatchSizesAsArray.length - 1];
return lastBatchSize == 0;
}

private PerfIssue verifyBatchSize(int expectedBatchSize, int[] measuredBatchSizesAsArray) {
int numberOfBatchSizeToCheck = findNumberOfBatchSizeToCheck(measuredBatchSizesAsArray);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* 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.
*
* Copyright 2019-2022 the original author or authors.
*/
package org.quickperf.sql.batch;

import org.junit.Test;
import org.quickperf.issue.PerfIssue;
import org.quickperf.sql.annotation.ExpectJdbcBatching;
import org.quickperf.sql.annotation.SqlAnnotationBuilder;

import static org.assertj.core.api.Assertions.assertThat;

public class SqlStatementBatchVerifierTest {

private final ExpectJdbcBatching expectJdbcBatchingWithBatchSizeOfThree = SqlAnnotationBuilder.expectJdbcBatching(3);

@Test public void
should_return_a_perf_issue_if_a_not_batched_execution_follows_a_batch() {

// GIVEN
SqlBatchSizes measuredBatchSizes = new SqlBatchSizes(new int[] {3, 0});

// WHEN
PerfIssue perfIssue = SqlStatementBatchVerifier.INSTANCE.verifyPerfIssue(expectJdbcBatchingWithBatchSizeOfThree, measuredBatchSizes);

// THEN
assertThat(perfIssue.getDescription()).isEqualTo("Expected batch size <3> but is <0>.");

}

@Test public void
should_return_no_perf_issue_if_the_last_batch_is_smaller_than_the_expected_batch_size() {

// GIVEN
SqlBatchSizes measuredBatchSizes = new SqlBatchSizes(new int[] {3, 2});

// WHEN
PerfIssue perfIssue = SqlStatementBatchVerifier.INSTANCE.verifyPerfIssue(expectJdbcBatchingWithBatchSizeOfThree, measuredBatchSizes);

// THEN
assertThat(perfIssue).isEqualTo(PerfIssue.NONE);

}

@Test public void
should_return_no_perf_issue_without_insert_update_and_delete_executions() {

// GIVEN
SqlBatchSizes measuredBatchSizes = new SqlBatchSizes(new int[0]);

// WHEN
PerfIssue perfIssue = SqlStatementBatchVerifier.INSTANCE.verifyPerfIssue(expectJdbcBatchingWithBatchSizeOfThree, measuredBatchSizes);

// THEN
assertThat(perfIssue).isEqualTo(PerfIssue.NONE);

}

@Test public void
should_return_no_perf_issue_if_batching_is_expected_to_be_disabled_and_executions_are_not_batched() {

// GIVEN
ExpectJdbcBatching expectJdbcBatchingWithZeroBatchSize = SqlAnnotationBuilder.expectJdbcBatching(0);
SqlBatchSizes measuredBatchSizes = new SqlBatchSizes(new int[] {0});

// WHEN
PerfIssue perfIssue = SqlStatementBatchVerifier.INSTANCE.verifyPerfIssue(expectJdbcBatchingWithZeroBatchSize, measuredBatchSizes);

// THEN
assertThat(perfIssue).isEqualTo(PerfIssue.NONE);

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
import org.quickperf.sql.config.MemoryDatabaseHibernateDialect;

import javax.persistence.Query;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -237,6 +240,92 @@ public void execute_two_insert_query_not_batched() {

}

@RunWith(QuickPerfJUnitRunner.class)
public static class AClassHavingAMethodAnnotatedWithExpectJdbcBatchingAndExecutingANotBatchedInsertAfterABatch extends SqlTestBase {

private static final int BATCH_SIZE = 30;

@Override
protected Properties getHibernateProperties() {
String hibernateDialect = MemoryDatabaseHibernateDialect.INSTANCE.getHibernateDialect();
return anHibernateConfig()
.withBatchSize(BATCH_SIZE)
.build(hibernateDialect);
}

@Test
@ExpectJdbcBatching(batchSize = BATCH_SIZE)
public void execute_a_not_batched_insert_query_after_a_batch() {

executeInATransaction(entityManager -> {
for (int i = 0; i < BATCH_SIZE; i++) {
Book newBook = new Book();
newBook.setTitle("new book");
entityManager.persist(newBook);
}
entityManager.flush();

String insertQueryAsString = "INSERT INTO Book (id,title) VALUES (1200, 'Book title')";
Query insertQuery = entityManager.createNativeQuery(insertQueryAsString);
insertQuery.executeUpdate();
});

}

}

@Test public void
should_fail_with_a_not_batched_insert_query_executed_after_a_batch() {

Class<?> testClass = AClassHavingAMethodAnnotatedWithExpectJdbcBatchingAndExecutingANotBatchedInsertAfterABatch.class;

PrintableResult printableResult = testResult(testClass);

assertThat(printableResult.failureCount()).isOne();

String testReport = printableResult.toString();
assertThat(testReport).contains("[PERF] Expected batch size <30> but is <0>.");

}

@RunWith(QuickPerfJUnitRunner.class)
public static class AClassHavingAMethodAnnotatedWithExpectJdbcBatchingAndExecutingAnEmptyBatchAfterBatches extends SqlTestBase {

private static final int BATCH_SIZE = 30;

@Test
@ExpectJdbcBatching(batchSize = BATCH_SIZE)
public void execute_an_empty_batch_after_batches() throws SQLException {

try (Connection connection = getConnection();
PreparedStatement insertStatement = connection.prepareStatement("INSERT INTO Book (id,title) VALUES (?, ?)")) {
for (int i = 1; i <= 2 * BATCH_SIZE; i++) {
insertStatement.setLong(1, 1200 + i);
insertStatement.setString(2, "Book title");
insertStatement.addBatch();
if (i % BATCH_SIZE == 0) {
insertStatement.executeBatch();
}
}
// Executes the remaining statements: none here
insertStatement.executeBatch();
}

}

}

@Test public void
should_pass_with_an_empty_batch_executed_after_batches() {

Class<?> testClass = AClassHavingAMethodAnnotatedWithExpectJdbcBatchingAndExecutingAnEmptyBatchAfterBatches.class;

PrintableResult printableResult = testResult(testClass);

assertThat(printableResult.failureCount()).isZero();

}

@RunWith(QuickPerfJUnitRunner.class)
public static class AClassHavingAMethodAnnotatedWithExpectJdbcBatchingAndWithBatchSizeDifferentFromTheExpectedOne extends SqlTestBase {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
import org.quickperf.sql.config.MemoryDatabaseHibernateDialect;

import javax.persistence.Query;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -180,4 +183,36 @@ public void execute_one_insert_in_batch_mode() {

}

@RunWith(QuickPerfJUnitRunner.class)
public static class AClassHavingAMethodAnnotatedWithExpectJdbcBatchingAndExecutingAnEmptyBatchAfterABatch extends SqlTestBase {

@Test
@ExpectJdbcBatching()
public void execute_an_empty_batch_after_a_batch() throws SQLException {

try (Connection connection = getConnection();
PreparedStatement insertStatement = connection.prepareStatement("INSERT INTO Book (id,title) VALUES (?, ?)")) {
insertStatement.setLong(1, 1200);
insertStatement.setString(2, "Book title");
insertStatement.addBatch();
insertStatement.executeBatch();

insertStatement.executeBatch();
}

}

}

@Test public void
should_pass_with_an_empty_batch_executed_after_a_batch() {

Class<?> testClass = AClassHavingAMethodAnnotatedWithExpectJdbcBatchingAndExecutingAnEmptyBatchAfterABatch.class;

PrintableResult testResult = testResult(testClass);

assertThat(testResult.failureCount()).isZero();

}

}
Loading