diff --git a/junit4/junit4-sql-test/src/test/java/org/quickperf/sql/DisableQuickPerfFeaturesJUnit4Test.java b/junit4/junit4-sql-test/src/test/java/org/quickperf/sql/DisableQuickPerfFeaturesJUnit4Test.java index af2e9297..b0202bed 100644 --- a/junit4/junit4-sql-test/src/test/java/org/quickperf/sql/DisableQuickPerfFeaturesJUnit4Test.java +++ b/junit4/junit4-sql-test/src/test/java/org/quickperf/sql/DisableQuickPerfFeaturesJUnit4Test.java @@ -19,6 +19,7 @@ import org.quickperf.annotation.FunctionalIteration; import org.quickperf.junit4.QuickPerfJUnitRunner; import org.quickperf.sql.annotation.ExpectSelect; +import org.quickperf.sql.annotation.ExpectSelects; import javax.persistence.EntityManager; import javax.persistence.Query; @@ -39,6 +40,18 @@ public void execute_one_select_but_five_select_expected() { query.getResultList(); } + @DisableQuickPerf + @ExpectSelects({ + @ExpectSelect(comment = "Select books"), + @ExpectSelect(comment = "Select related entities", value = 4) + }) + @Test + public void execute_one_select_but_five_select_expected_with_repeated_annotations() { + EntityManager em = emf.createEntityManager(); + Query query = em.createQuery("FROM " + Book.class.getCanonicalName()); + query.getResultList(); + } + } @Test public void @@ -67,6 +80,18 @@ public void execute_one_select_but_five_select_expected() { query.getResultList(); } + @FunctionalIteration + @ExpectSelects({ + @ExpectSelect(comment = "Select books"), + @ExpectSelect(comment = "Select related entities", value = 4) + }) + @Test + public void execute_one_select_but_five_select_expected_with_repeated_annotations() { + EntityManager em = emf.createEntityManager(); + Query query = em.createQuery("FROM " + Book.class.getCanonicalName()); + query.getResultList(); + } + } @Test public void diff --git a/junit4/junit4-sql-test/src/test/java/org/quickperf/sql/SqlConcurrencyJUnit4Test.java b/junit4/junit4-sql-test/src/test/java/org/quickperf/sql/SqlConcurrencyJUnit4Test.java index e9431219..58ecb077 100644 --- a/junit4/junit4-sql-test/src/test/java/org/quickperf/sql/SqlConcurrencyJUnit4Test.java +++ b/junit4/junit4-sql-test/src/test/java/org/quickperf/sql/SqlConcurrencyJUnit4Test.java @@ -19,6 +19,7 @@ import org.junit.runner.RunWith; import org.quickperf.junit4.QuickPerfJUnitRunner; import org.quickperf.sql.annotation.ExpectSelect; +import org.quickperf.sql.annotation.ExpectSelects; import javax.persistence.EntityManager; import javax.persistence.Query; @@ -39,9 +40,21 @@ public void execute_one_select() { query.getResultList(); } + @ExpectSelects({ + @ExpectSelect(comment = "Select books.") + }) + @Test + public void execute_one_select_with_repeatable_annotation() { + EntityManager em = emf.createEntityManager(); + Query query = em.createQuery("FROM " + Book.class.getCanonicalName()); + query.getResultList(); + } + } - - @ThreadCount(100) @Test public void + + @ThreadCount(100) + @Test + public void sql_performance_property_is_ok() { Class testClass = AClassHavingAMethodWithoutSqlPerformanceIssue.class; diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectDelete.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectDelete.java index 08b9df7c..fc89d00c 100644 --- a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectDelete.java +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectDelete.java @@ -40,4 +40,10 @@ */ int value() default 1; + /** + * To comment on the reason why we expect the specified amount of queries of this type. + * @return comment message + */ + String comment() default ""; + } diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectDeletes.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectDeletes.java new file mode 100644 index 00000000..765ecfa6 --- /dev/null +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectDeletes.java @@ -0,0 +1,45 @@ +/* + * 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.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The ExpectDeletes annotation verifies the number of executed delete statements corresponds to the + * specified values. + * + *

+ *

Example:

+ *
+ *      @ExpectDeletes({
+ *          @ExpectDelete(comment="Delete user"),
+ *          @ExpectDelete(comment="Delete posts",value=2)
+ *      })
+ *      public void execute_three_delete() {
+ *          ..
+ *      }
+ * 
+ */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface ExpectDeletes { + + /** + * Specifies an array of expected queries. + */ + ExpectDelete[] value(); + +} diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectInsert.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectInsert.java index 4e457b42..03377b1a 100644 --- a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectInsert.java +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectInsert.java @@ -41,4 +41,10 @@ int value() default 1; + /** + * To comment on the reason why we expect the specified amount of queries of this type. + * @return comment message + */ + String comment() default ""; + } diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectInserts.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectInserts.java new file mode 100644 index 00000000..ada6416b --- /dev/null +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectInserts.java @@ -0,0 +1,46 @@ +/* + * 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.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The ExpectInserts annotation verifies the number of executed insert statements corresponds to the + * specified values. + * + *

+ *

Example:

+ *
+ *      @ExpectInserts({
+ *          @ExpectInsert(comment="Insert user"),
+ *          @ExpectInsert(comment="Insert posts",value=2),
+ *          @ExpectInsert(comment="Insert comments",value=3)
+ *      })
+ *      public void execute_six_insert() {
+ *          ..
+ *      }
+ * 
+ */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface ExpectInserts { + + /** + * Specifies an array of expected queries. + */ + ExpectInsert[] value(); + +} diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectJdbcQueryExecution.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectJdbcQueryExecution.java index b7799842..16f8f6a5 100644 --- a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectJdbcQueryExecution.java +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectJdbcQueryExecution.java @@ -40,4 +40,10 @@ */ int value() default 1; + /** + * To comment on the reason why we expect the specified amount of queries of this type. + * @return comment message + */ + String comment() default ""; + } diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectSelect.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectSelect.java index 571795ed..cf3b78b7 100644 --- a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectSelect.java +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectSelect.java @@ -40,4 +40,10 @@ */ int value() default 1; + /** + * To comment on the reason why we expect the specified amount of queries of this type. + * @return comment message + */ + String comment() default ""; + } diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectSelects.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectSelects.java new file mode 100644 index 00000000..11b81b06 --- /dev/null +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectSelects.java @@ -0,0 +1,45 @@ +/* + * 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.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The ExpectSelects annotation verifies the number of executed select statements corresponds to the + * specified values. + * + *

+ *

Example:

+ *
+ *      @ExpectSelects({
+ *          @ExpectSelect(comment="Load post"),
+ *          @ExpectSelect(comment="Load comments",value=2)
+ *      })
+ *      public void execute_three_selects() {
+ *          ..
+ *      }
+ * 
+ */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE}) +public @interface ExpectSelects { + + /** + * Specifies an array of expected queries. + */ + ExpectSelect[] value(); + +} diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectUpdate.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectUpdate.java index 6aeb70fc..0c0c7a48 100644 --- a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectUpdate.java +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectUpdate.java @@ -40,4 +40,10 @@ */ int value() default 1; + /** + * To comment on the reason why we expect the specified amount of queries of this type. + * @return comment message + */ + String comment() default ""; + } diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectUpdates.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectUpdates.java new file mode 100644 index 00000000..d3945e44 --- /dev/null +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/ExpectUpdates.java @@ -0,0 +1,45 @@ +/* + * 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.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The ExpectUpdates annotation verifies the number of executed update statements corresponds to the + * specified values. + * + *

+ *

Example:

+ *
+ *      @ExpectUpdates({
+ *          @ExpectUpdate(comment="Update post"),
+ *          @ExpectUpdate(comment="Update comments",value=2)
+ *      })
+ *      public void execute_three_update() {
+ *          ..
+ *      }
+ * 
+ */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface ExpectUpdates { + + /** + * Specifies an array of expected queries. + */ + ExpectUpdate[] value(); + +} diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/SqlAnnotationBuilder.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/SqlAnnotationBuilder.java index 3a7a9575..0857c18f 100644 --- a/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/SqlAnnotationBuilder.java +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/annotation/SqlAnnotationBuilder.java @@ -134,6 +134,10 @@ public Class annotationType() { public int value() { return value; } + @Override + public String comment() { + return ""; + } }; } @@ -231,6 +235,10 @@ public Class annotationType() { public int value() { return value; } + @Override + public String comment() { + return ""; + } }; } @@ -247,6 +255,10 @@ public Class annotationType() { public int value() { return value; } + @Override + public String comment() { + return ""; + } }; } @@ -263,6 +275,10 @@ public Class annotationType() { public int value() { return value; } + @Override + public String comment() { + return ""; + } }; } @@ -279,6 +295,74 @@ public Class annotationType() { public int value() { return value; } + @Override + public String comment() { + return ""; + } + }; + } + + /** + *Allows to build {@link org.quickperf.sql.annotation.ExpectDeletes} annotation. + */ + public static ExpectDeletes expectDeletes(final ExpectDelete... value) { + return new ExpectDeletes() { + @Override + public Class annotationType() { + return ExpectDeletes.class; + } + @Override + public ExpectDelete[] value() { + return value; + } + }; + } + + /** + *Allows to build {@link org.quickperf.sql.annotation.ExpectInserts} annotation. + */ + public static ExpectInserts expectInserts(final ExpectInsert... value) { + return new ExpectInserts() { + @Override + public Class annotationType() { + return ExpectInserts.class; + } + @Override + public ExpectInsert[] value() { + return value; + } + }; + } + + /** + *Allows to build {@link org.quickperf.sql.annotation.ExpectSelects} annotation. + */ + public static ExpectSelects expectSelects(final ExpectSelect... value) { + return new ExpectSelects() { + @Override + public Class annotationType() { + return ExpectSelects.class; + } + @Override + public ExpectSelect[] value() { + return value; + } + }; + } + + /** + *Allows to build {@link org.quickperf.sql.annotation.ExpectUpdates} annotation. + */ + public static ExpectUpdates expectUpdates(final ExpectUpdate... value) { + return new ExpectUpdates() { + @Override + public Class annotationType() { + return ExpectUpdates.class; + } + @Override + public ExpectUpdate[] value() { + return value; + } }; } diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/config/library/SqlAnnotationsConfigs.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/config/library/SqlAnnotationsConfigs.java index 6772a457..28317a0f 100644 --- a/sql/sql-annotations/src/main/java/org/quickperf/sql/config/library/SqlAnnotationsConfigs.java +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/config/library/SqlAnnotationsConfigs.java @@ -27,18 +27,17 @@ import org.quickperf.sql.delete.DeleteCountMeasureExtractor; import org.quickperf.sql.delete.MaxOfDeletesPerfIssueVerifier; import org.quickperf.sql.delete.NumberOfSqlDeletePerfIssueVerifier; +import org.quickperf.sql.delete.NumberOfSqlDeletesPerfIssueVerifier; import org.quickperf.sql.display.DisplaySqlOfTestMethodBodyRecorder; import org.quickperf.sql.display.DisplaySqlRecorder; import org.quickperf.sql.execution.*; import org.quickperf.sql.insert.InsertCountMeasureExtractor; import org.quickperf.sql.insert.InsertNumberPerfIssueVerifier; import org.quickperf.sql.insert.MaxOfInsertsPerfIssueVerifier; +import org.quickperf.sql.insert.NumberOfSqlInsertsPerfIssueVerifier; import org.quickperf.sql.like.ContainsLikeWithLeadingWildcardExtractor; import org.quickperf.sql.like.HasLikeWithLeadingWildcardVerifier; -import org.quickperf.sql.select.HasExactlySameSelectVerifier; -import org.quickperf.sql.select.HasSameSelectTypesWithDiffParamValuesVerifier; -import org.quickperf.sql.select.MaxOfSelectsPerfIssueVerifier; -import org.quickperf.sql.select.SelectNumberPerfIssueVerifier; +import org.quickperf.sql.select.*; import org.quickperf.sql.select.analysis.SelectAnalysisExtractor; import org.quickperf.sql.select.columns.MaxSelectedColumnsPerMeasureExtractor; import org.quickperf.sql.select.columns.MaxSelectedColumnsPerfIssueVerifier; @@ -49,6 +48,7 @@ import org.quickperf.sql.time.SqlQueryExecutionTimeExtractor; import org.quickperf.sql.time.SqlQueryMaxExecutionTimeVerifier; import org.quickperf.sql.update.MaxOfUpdatesPerfIssueVerifier; +import org.quickperf.sql.update.NumberOfSqlUpdatesPerfIssueVerifier; import org.quickperf.sql.update.UpdateCountMeasureExtractor; import org.quickperf.sql.update.UpdateNumberPerfIssueVerifier; import org.quickperf.sql.update.columns.MaxUpdatedColumnsPerMeasureExtractor; @@ -88,6 +88,12 @@ private SqlAnnotationsConfigs() { } .perfIssueVerifier(SelectNumberPerfIssueVerifier.INSTANCE) .build(ExpectSelect.class); + static final AnnotationConfig NUMBER_OF_SQL_SELECTS = new AnnotationConfig.Builder() + .perfRecorderClass(PersistenceSqlRecorder.class) + .perfMeasureExtractor(SelectAnalysisExtractor.INSTANCE) + .perfIssueVerifier(NumberOfSqlSelectsPerfIssueVerifier.INSTANCE) + .build(ExpectSelects.class); + static final AnnotationConfig MAX_SQL_SELECT = new AnnotationConfig.Builder() .perfRecorderClass(PersistenceSqlRecorder.class) .perfMeasureExtractor(SelectAnalysisExtractor.INSTANCE) @@ -134,6 +140,12 @@ private SqlAnnotationsConfigs() { } .perfIssueVerifier(InsertNumberPerfIssueVerifier.INSTANCE) .build(ExpectInsert.class); + static final AnnotationConfig NUMBER_OF_SQL_INSERTS = new AnnotationConfig.Builder() + .perfRecorderClass(PersistenceSqlRecorder.class) + .perfMeasureExtractor(InsertCountMeasureExtractor.INSTANCE) + .perfIssueVerifier(NumberOfSqlInsertsPerfIssueVerifier.INSTANCE) + .build(ExpectInserts.class); + static final AnnotationConfig SQL_STATEMENTS_BATCHED = new AnnotationConfig.Builder() .perfRecorderClass(SqlStatementBatchRecorder.class) .perfIssueVerifier(SqlStatementBatchVerifier.INSTANCE) @@ -145,12 +157,24 @@ private SqlAnnotationsConfigs() { } .perfIssueVerifier(NumberOfSqlDeletePerfIssueVerifier.INSTANCE) .build(ExpectDelete.class); + static final AnnotationConfig NUMBER_OF_SQL_DELETES = new AnnotationConfig.Builder() + .perfRecorderClass(PersistenceSqlRecorder.class) + .perfMeasureExtractor(DeleteCountMeasureExtractor.INSTANCE) + .perfIssueVerifier(NumberOfSqlDeletesPerfIssueVerifier.INSTANCE) + .build(ExpectDeletes.class); + static final AnnotationConfig NUMBER_OF_SQL_UPDATE = new AnnotationConfig.Builder() .perfRecorderClass(PersistenceSqlRecorder.class) .perfMeasureExtractor(UpdateCountMeasureExtractor.INSTANCE) .perfIssueVerifier(UpdateNumberPerfIssueVerifier.INSTANCE) .build(ExpectUpdate.class); + static final AnnotationConfig NUMBER_OF_SQL_UPDATES = new AnnotationConfig.Builder() + .perfRecorderClass(PersistenceSqlRecorder.class) + .perfMeasureExtractor(UpdateCountMeasureExtractor.INSTANCE) + .perfIssueVerifier(NumberOfSqlUpdatesPerfIssueVerifier.INSTANCE) + .build(ExpectUpdates.class); + static final AnnotationConfig MAX_SQL_UPDATE = new AnnotationConfig.Builder() .perfRecorderClass(PersistenceSqlRecorder.class) .perfMeasureExtractor(UpdateCountMeasureExtractor.INSTANCE) diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/config/library/SqlConfigLoader.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/config/library/SqlConfigLoader.java index 7e1c466b..b5c73fd4 100644 --- a/sql/sql-annotations/src/main/java/org/quickperf/sql/config/library/SqlConfigLoader.java +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/config/library/SqlConfigLoader.java @@ -33,9 +33,13 @@ public Collection loadAnnotationConfigs() { SqlAnnotationsConfigs.JDBC_QUERY_EXECUTION , SqlAnnotationsConfigs.MAX_JDBC_QUERY_EXECUTION , SqlAnnotationsConfigs.NUMBER_OF_SQL_SELECT + , SqlAnnotationsConfigs.NUMBER_OF_SQL_SELECTS , SqlAnnotationsConfigs.NUMBER_OF_SQL_INSERT + , SqlAnnotationsConfigs.NUMBER_OF_SQL_INSERTS , SqlAnnotationsConfigs.NUMBER_OF_SQL_UPDATE + , SqlAnnotationsConfigs.NUMBER_OF_SQL_UPDATES , SqlAnnotationsConfigs.NUMBER_OF_SQL_DELETE + , SqlAnnotationsConfigs.NUMBER_OF_SQL_DELETES , SqlAnnotationsConfigs.MAX_SQL_SELECT , SqlAnnotationsConfigs.MAX_SQL_INSERT , SqlAnnotationsConfigs.MAX_SQL_UPDATE diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/delete/NumberOfSqlDeletesPerfIssueVerifier.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/delete/NumberOfSqlDeletesPerfIssueVerifier.java new file mode 100644 index 00000000..9ddea6e6 --- /dev/null +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/delete/NumberOfSqlDeletesPerfIssueVerifier.java @@ -0,0 +1,50 @@ +/* + * 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.delete; + +import org.quickperf.issue.PerfIssue; +import org.quickperf.issue.VerifiablePerformanceIssue; +import org.quickperf.sql.annotation.ExpectDelete; +import org.quickperf.sql.annotation.ExpectDeletes; +import org.quickperf.unit.Count; + +import java.util.Arrays; + +import static org.quickperf.sql.SqlStatementPerfIssueBuilder.aSqlPerfIssue; + +public class NumberOfSqlDeletesPerfIssueVerifier implements VerifiablePerformanceIssue { + + public static final NumberOfSqlDeletesPerfIssueVerifier INSTANCE = new NumberOfSqlDeletesPerfIssueVerifier(); + + private NumberOfSqlDeletesPerfIssueVerifier() { + } + + @Override + public PerfIssue verifyPerfIssue(final ExpectDeletes annotation, final Count measuredCount) { + + int sum = 0; + for (ExpectDelete expectDelete : annotation.value()) { + sum += expectDelete.value(); + } + final Count expectedCount = new Count(sum); + + if (!measuredCount.isEqualTo(expectedCount)) { + return aSqlPerfIssue().buildNotEqualNumberOfStatements( + measuredCount, expectedCount, "DELETE"); + } + + return PerfIssue.NONE; + + } + +} \ No newline at end of file diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/insert/NumberOfSqlInsertsPerfIssueVerifier.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/insert/NumberOfSqlInsertsPerfIssueVerifier.java new file mode 100644 index 00000000..929a37ca --- /dev/null +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/insert/NumberOfSqlInsertsPerfIssueVerifier.java @@ -0,0 +1,50 @@ +/* + * 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.insert; + +import org.quickperf.issue.PerfIssue; +import org.quickperf.issue.VerifiablePerformanceIssue; +import org.quickperf.sql.annotation.ExpectInsert; +import org.quickperf.sql.annotation.ExpectInserts; +import org.quickperf.unit.Count; + +import java.util.Arrays; + +import static org.quickperf.sql.SqlStatementPerfIssueBuilder.aSqlPerfIssue; + +public class NumberOfSqlInsertsPerfIssueVerifier implements VerifiablePerformanceIssue { + + public static final NumberOfSqlInsertsPerfIssueVerifier INSTANCE = new NumberOfSqlInsertsPerfIssueVerifier(); + + private NumberOfSqlInsertsPerfIssueVerifier() { + } + + @Override + public PerfIssue verifyPerfIssue(final ExpectInserts annotation, final Count measuredCount) { + + int sum = 0; + for (ExpectInsert expectInsert : annotation.value()) { + sum += expectInsert.value(); + } + final Count expectedCount = new Count(sum); + + if (!measuredCount.isEqualTo(expectedCount)) { + return aSqlPerfIssue().buildNotEqualNumberOfStatements( + measuredCount, expectedCount, "INSERT"); + } + + return PerfIssue.NONE; + + } + +} \ No newline at end of file diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/select/NumberOfSqlSelectsPerfIssueVerifier.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/select/NumberOfSqlSelectsPerfIssueVerifier.java new file mode 100644 index 00000000..6ae7756a --- /dev/null +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/select/NumberOfSqlSelectsPerfIssueVerifier.java @@ -0,0 +1,52 @@ +/* + * 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.select; + +import org.quickperf.issue.PerfIssue; +import org.quickperf.issue.VerifiablePerformanceIssue; +import org.quickperf.sql.annotation.ExpectSelect; +import org.quickperf.sql.annotation.ExpectSelects; +import org.quickperf.sql.select.analysis.SelectAnalysis; +import org.quickperf.unit.Count; + +import java.util.Arrays; + +import static org.quickperf.sql.SqlStatementPerfIssueBuilder.aSqlPerfIssue; + +public class NumberOfSqlSelectsPerfIssueVerifier implements VerifiablePerformanceIssue { + + public static final NumberOfSqlSelectsPerfIssueVerifier INSTANCE = new NumberOfSqlSelectsPerfIssueVerifier(); + + private NumberOfSqlSelectsPerfIssueVerifier() { + } + + @Override + public PerfIssue verifyPerfIssue(final ExpectSelects annotation, final SelectAnalysis analysis) { + + int sum = 0; + for (ExpectSelect expectSelect : annotation.value()) { + sum += expectSelect.value(); + } + final Count expectedCount = new Count(sum); + + final Count measuredCount = analysis.getSelectNumber(); + if (!measuredCount.isEqualTo(expectedCount)) { + return aSqlPerfIssue().buildNotEqualNumberOfStatements( + measuredCount, expectedCount, "SELECT"); + } + + return PerfIssue.NONE; + + } + +} \ No newline at end of file diff --git a/sql/sql-annotations/src/main/java/org/quickperf/sql/update/NumberOfSqlUpdatesPerfIssueVerifier.java b/sql/sql-annotations/src/main/java/org/quickperf/sql/update/NumberOfSqlUpdatesPerfIssueVerifier.java new file mode 100644 index 00000000..7301ea63 --- /dev/null +++ b/sql/sql-annotations/src/main/java/org/quickperf/sql/update/NumberOfSqlUpdatesPerfIssueVerifier.java @@ -0,0 +1,50 @@ +/* + * 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.update; + +import org.quickperf.issue.PerfIssue; +import org.quickperf.issue.VerifiablePerformanceIssue; +import org.quickperf.sql.annotation.ExpectUpdate; +import org.quickperf.sql.annotation.ExpectUpdates; +import org.quickperf.unit.Count; + +import java.util.Arrays; + +import static org.quickperf.sql.SqlStatementPerfIssueBuilder.aSqlPerfIssue; + +public class NumberOfSqlUpdatesPerfIssueVerifier implements VerifiablePerformanceIssue { + + public static final NumberOfSqlUpdatesPerfIssueVerifier INSTANCE = new NumberOfSqlUpdatesPerfIssueVerifier(); + + private NumberOfSqlUpdatesPerfIssueVerifier() { + } + + @Override + public PerfIssue verifyPerfIssue(final ExpectUpdates annotation, final Count measuredCount) { + + int sum = 0; + for (ExpectUpdate expectUpdate : annotation.value()) { + sum += expectUpdate.value(); + } + final Count expectedCount = new Count(sum); + + if (!measuredCount.isEqualTo(expectedCount)) { + return aSqlPerfIssue().buildNotEqualNumberOfStatements( + measuredCount, expectedCount, "UPDATE"); + } + + return PerfIssue.NONE; + + } + +} \ No newline at end of file diff --git a/sql/sql-memory-test/src/test/java/ExpectDeleteTest.java b/sql/sql-memory-test/src/test/java/ExpectDeleteTest.java index 950cdcc1..50e6c129 100644 --- a/sql/sql-memory-test/src/test/java/ExpectDeleteTest.java +++ b/sql/sql-memory-test/src/test/java/ExpectDeleteTest.java @@ -16,6 +16,7 @@ import org.quickperf.junit4.QuickPerfJUnitRunner; import org.quickperf.sql.Book; import org.quickperf.sql.annotation.ExpectDelete; +import org.quickperf.sql.annotation.ExpectDeletes; import javax.persistence.EntityManager; import javax.persistence.Query; @@ -44,6 +45,28 @@ public void execute_one_delete_but_five_deletes_expected() { } + @RunWith(QuickPerfJUnitRunner.class) + public static class SqlDeletes extends SqlTestBase { + + @ExpectDeletes({ + @ExpectDelete(comment = "Delete book"), + @ExpectDelete(comment = "Delete users", value = 4) + }) + @Test + public void execute_one_delete_but_five_deletes_expected() { + + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + + Query query = em.createQuery("DELETE FROM " + Book.class.getCanonicalName()); + query.executeUpdate(); + + em.getTransaction().commit(); + + } + + } + @Test public void should_fail_if_the_number_of_delete_statements_is_not_equal_to_the_number_expected() { @@ -54,6 +77,25 @@ public void execute_one_delete_but_five_deletes_expected() { PrintableResult printableResult = testResult(testClass); // THEN + assertResultMatchesExpectations(printableResult); + + } + + @Test public void + should_fail_if_the_number_of_delete_statements_is_not_equal_to_the_number_expected_with_repeatable_annotation() { + + // GIVEN + Class testClass = SqlDeletes.class; + + // WHEN + PrintableResult printableResult = testResult(testClass); + + // THEN + assertResultMatchesExpectations(printableResult); + + } + + private static void assertResultMatchesExpectations(PrintableResult printableResult) { assertThat(printableResult.failureCount()).isOne(); assertThat(printableResult.toString()) @@ -61,7 +103,6 @@ public void execute_one_delete_but_five_deletes_expected() { .contains("delete") .contains("from") .contains("Book"); - } } diff --git a/sql/sql-memory-test/src/test/java/ExpectInsertTest.java b/sql/sql-memory-test/src/test/java/ExpectInsertTest.java index 19bf10bc..e4e205c6 100644 --- a/sql/sql-memory-test/src/test/java/ExpectInsertTest.java +++ b/sql/sql-memory-test/src/test/java/ExpectInsertTest.java @@ -16,6 +16,7 @@ import org.quickperf.junit4.QuickPerfJUnitRunner; import org.quickperf.sql.Book; import org.quickperf.sql.annotation.ExpectInsert; +import org.quickperf.sql.annotation.ExpectInserts; import javax.persistence.EntityManager; @@ -46,6 +47,31 @@ public void execute_one_insert_but_five_inserts_expected() { } + @RunWith(QuickPerfJUnitRunner.class) + public static class SqlInserts extends SqlTestBase { + + @ExpectInserts({ + @ExpectInsert(comment = "Insert book"), + @ExpectInsert(comment = "Insert users", value = 4) + }) + @Test + public void execute_one_insert_but_five_inserts_expected() { + + EntityManager em = emf.createEntityManager(); + em.getTransaction().begin(); + + Book effectiveJava = new Book(); + effectiveJava.setIsbn("effectiveJavaIsbn"); + effectiveJava.setTitle("Effective Java"); + + em.persist(effectiveJava); + + em.getTransaction().commit(); + + } + + } + @Test public void should_fail_if_the_number_of_insert_statements_is_not_equal_to_the_number_expected() { @@ -56,6 +82,25 @@ public void execute_one_insert_but_five_inserts_expected() { PrintableResult printableResult = testResult(testClass); // THEN + assertResultMatchesExpectations(printableResult); + + } + + @Test public void + should_fail_if_the_number_of_insert_statements_is_not_equal_to_the_number_expected_with_repeatable_annotation() { + + // GIVEN + Class testClass = SqlInserts.class; + + // WHEN + PrintableResult printableResult = testResult(testClass); + + // THEN + assertResultMatchesExpectations(printableResult); + + } + + private static void assertResultMatchesExpectations(PrintableResult printableResult) { assertThat(printableResult.failureCount()).isOne(); assertThat(printableResult.toString()) @@ -64,7 +109,6 @@ public void execute_one_insert_but_five_inserts_expected() { .contains("into") .contains("Book") .contains("isbn, title, id)"); - } } diff --git a/sql/sql-memory-test/src/test/java/ExpectSelectTest.java b/sql/sql-memory-test/src/test/java/ExpectSelectTest.java index 9cfcf99e..a9b13f40 100644 --- a/sql/sql-memory-test/src/test/java/ExpectSelectTest.java +++ b/sql/sql-memory-test/src/test/java/ExpectSelectTest.java @@ -16,6 +16,7 @@ import org.quickperf.junit4.QuickPerfJUnitRunner; import org.quickperf.sql.Book; import org.quickperf.sql.annotation.ExpectSelect; +import org.quickperf.sql.annotation.ExpectSelects; import javax.persistence.EntityManager; import javax.persistence.Query; @@ -59,6 +60,42 @@ public void execute_one_select_but_five_select_expected() { } + @RunWith(QuickPerfJUnitRunner.class) + public static class AClassHavingAMethodAnnotatedWithExpectSelects extends SqlTestBase { + + @ExpectSelects({ + @ExpectSelect(comment = "Select books"), + @ExpectSelect(comment = "Select related entities", value = 4) + }) + @Test + public void execute_one_select_but_five_select_expected() { + EntityManager em = emf.createEntityManager(); + Query query = em.createQuery("FROM " + Book.class.getCanonicalName()); + query.getResultList(); + } + + } + + @Test public void + should_fail_if_the_number_of_select_statements_is_not_equal_to_the_number_expected_with_repeatable_annotation() { + + // GIVEN + Class testClass = AClassHavingAMethodAnnotatedWithExpectSelects.class; + + // WHEN + PrintableResult printableResult = testResult(testClass); + + // THEN + assertThat(printableResult.failureCount()).isOne(); + + String testResult = printableResult.toString(); + assertThat(testResult) + .contains("Expected number of SELECT statements <5> but is <1>.") + .contains("select") + .contains("book0_.id as id1_0"); + + } + @RunWith(QuickPerfJUnitRunner.class) public static class AClassHavingAMethodAnnotatedWithExpectSelectAndSelectsLessThanExpected extends SqlTestBase { diff --git a/sql/sql-memory-test/src/test/java/ExpectUpdateTest.java b/sql/sql-memory-test/src/test/java/ExpectUpdateTest.java index 7b8b8afd..f5a052da 100644 --- a/sql/sql-memory-test/src/test/java/ExpectUpdateTest.java +++ b/sql/sql-memory-test/src/test/java/ExpectUpdateTest.java @@ -15,6 +15,7 @@ import org.junit.runner.RunWith; import org.quickperf.junit4.QuickPerfJUnitRunner; import org.quickperf.sql.annotation.ExpectUpdate; +import org.quickperf.sql.annotation.ExpectUpdates; import javax.persistence.EntityManager; import javax.persistence.Query; @@ -48,6 +49,33 @@ public void execute_one_update_but_five_expected() { } + @RunWith(QuickPerfJUnitRunner.class) + public static class RepeatedSqlUpdate extends SqlTestBase { + + @ExpectUpdates({ + @ExpectUpdate(comment = "Update book"), + @ExpectUpdate(comment = "Update related objects", value = 4) + }) + @Test + public void execute_one_update_but_five_expected_with_repeatable_annotation() { + + EntityManager em = emf.createEntityManager(); + + em.getTransaction().begin(); + + String sql = " UPDATE book" + + " SET isbn ='978-0134685991'" + + " WHERE id = 1"; + Query query = em.createNativeQuery(sql); + + query.executeUpdate(); + + em.getTransaction().commit(); + + } + + } + @Test public void should_fail_if_the_number_of_update_statements_is_not_equal_to_the_number_expected() { @@ -58,6 +86,25 @@ public void execute_one_update_but_five_expected() { PrintableResult printableResult = testResult(testClass); // THEN + assertPrintableResultMatchesExpected(printableResult); + + } + + @Test public void + should_fail_if_the_number_of_update_statements_is_not_equal_to_the_number_expected_with_repeatable_annotation() { + + // GIVEN + Class testClass = RepeatedSqlUpdate.class; + + // WHEN + PrintableResult printableResult = testResult(testClass); + + // THEN + assertPrintableResultMatchesExpected(printableResult); + + } + + private static void assertPrintableResultMatchesExpected(PrintableResult printableResult) { assertThat(printableResult.failureCount()).isOne(); assertThat(printableResult.toString()) @@ -66,7 +113,6 @@ public void execute_one_update_but_five_expected() { .contains("book") .contains("SET") .contains("isbn"); - } }