/**
* Copyright (C) 2015 Orange
* 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.
*/
package com.francetelecom.clara.cloud.commons;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.stat.Statistics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Created with IntelliJ IDEA.
* User: shjn2064
* Date: 11/09/12
* Time: 16:30
* To change this template use File | Settings | File Templates.
*/
public class HibernateStatsHelper {
protected static Logger logger = LoggerFactory.getLogger(HibernateStatsHelper.class.getName());
/**
* check all statistics including durations
* @param refs
* @param duration total duration of test
* @param stats
*/
public static void checkStats(Map<HibernateStatsReferenceType, Long> refs, long duration, Statistics stats) throws ObjectNotFoundException, MalformedURLException {
checkStats(refs, duration, stats, true);
}
/**
* check statistics ignoring durations<br>
* this method shall be used when we don't want to fail a test due to test environment slow response time
* note: durations may still be provided in refs or stats but are not verified<br>
*
* @param refs
* @param stats
*/
public static void checkStatsIgnoringDuration(Map<HibernateStatsReferenceType, Long> refs, Statistics stats) throws ObjectNotFoundException, MalformedURLException {
checkStats(refs, 0, stats, false);
}
/**
* Ensure no regression higher than 5%
* @param assertDuration if true durations are verified, if false durations are not verified
*/
private static void checkStats(Map<HibernateStatsReferenceType, Long> refs, long duration, Statistics stats, boolean assertDuration) throws ObjectNotFoundException, MalformedURLException {
List<AssertionError> failedAsserts = new ArrayList<AssertionError>();
// Reference values: these must be updated when you optimize your code
// or if new values are explained and normal.
final long DURATION = refs.get(HibernateStatsReferenceType.DURATION);
final int QUERY_COUNT = refs.get(HibernateStatsReferenceType.QUERY_COUNT).intValue();
final int QUERY_MAX_TIME_MS = refs.get(HibernateStatsReferenceType.QUERY_MAX_TIME_MS).intValue();
final int ENTITY_FETCH_COUNT = refs.get(HibernateStatsReferenceType.ENTITY_FETCH_COUNT).intValue();
final int ENTITY_LOAD_COUNT = refs.get(HibernateStatsReferenceType.ENTITY_LOAD_COUNT).intValue();
final int ENTITY_INSERT_COUNT = refs.get(HibernateStatsReferenceType.ENTITY_INSERT_COUNT).intValue();
final int ENTITY_DELETE_COUNT = refs.get(HibernateStatsReferenceType.ENTITY_DELETE_COUNT).intValue();
final int ENTITY_UPDATE_COUNT = refs.get(HibernateStatsReferenceType.ENTITY_UPDATE_COUNT).intValue();
final int COLLECTION_FETCH_COUNT = refs.get(HibernateStatsReferenceType.COLLECTION_FETCH_COUNT).intValue();
final int COLLECTION_LOAD_COUNT = refs.get(HibernateStatsReferenceType.COLLECTION_LOAD_COUNT).intValue();
final int COLLECTION_RECREATE_COUNT = refs.get(HibernateStatsReferenceType.COLLECTION_RECREATE_COUNT).intValue();
final int COLLECTION_REMOVE_COUNT = refs.get(HibernateStatsReferenceType.COLLECTION_REMOVE_COUNT).intValue();
final int COLLECTION_UPDATE_COUNT = refs.get(HibernateStatsReferenceType.COLLECTION_UPDATE_COUNT).intValue();
// The number of completed transactions (failed and successful) must
// match number of transactions completed without failure
preAssertEquals("There are transaction failures", stats.getTransactionCount(), stats.getSuccessfulTransactionCount(), failedAsserts);
// Total number of queries executed.
preAssertTrue("Total number of queries executed increased more than 5% (ref=" + QUERY_COUNT + "): " + stats.getQueryExecutionCount(),
stats.getQueryExecutionCount() <= (QUERY_COUNT * 1.05), failedAsserts);
if (stats.getQueryExecutionCount() < (QUERY_COUNT * 0.95))
logger.warn("/!\\ You should update reference value QUERY_COUNT (ref=" + QUERY_COUNT + ") to " + stats.getQueryExecutionCount());
preAssertTrue("ENTITY_DELETE_COUNT increased more than 5% (ref=" + ENTITY_DELETE_COUNT + "): " + stats.getEntityDeleteCount(),
stats.getEntityDeleteCount() <= (ENTITY_DELETE_COUNT * 1.05), failedAsserts);
if (stats.getEntityDeleteCount() < (ENTITY_DELETE_COUNT * 0.95))
logger.warn("/!\\ You should update reference value ENTITY_DELETE_COUNT (ref=" + ENTITY_DELETE_COUNT + ") to " + stats.getEntityDeleteCount());
preAssertTrue("ENTITY_UPDATE_COUNT increased more than 5% (ref=" + ENTITY_UPDATE_COUNT + "): " + stats.getEntityUpdateCount(),
stats.getEntityUpdateCount() <= (ENTITY_UPDATE_COUNT * 1.05), failedAsserts);
if (stats.getEntityUpdateCount() < (ENTITY_UPDATE_COUNT * 0.95))
logger.warn("/!\\ You should update reference value ENTITY_UPDATE_COUNT (ref=" + ENTITY_UPDATE_COUNT + ") to " + stats.getEntityUpdateCount());
if (stats.getCollectionRecreateCount() < (COLLECTION_RECREATE_COUNT * 0.95))
logger.warn("/!\\ You should update reference value COLLECTION_RECREATE_COUNT (ref=" + COLLECTION_RECREATE_COUNT + ") to "
+ stats.getCollectionRecreateCount());
preAssertTrue("COLLECTION_REMOVE_COUNT increased more than 5% (ref=" + COLLECTION_REMOVE_COUNT + "): " + stats.getCollectionRemoveCount(),
stats.getCollectionRemoveCount() <= (COLLECTION_REMOVE_COUNT * 1.05), failedAsserts);
if (stats.getCollectionRemoveCount() < (COLLECTION_REMOVE_COUNT * 0.95))
logger.warn("/!\\ You should update reference value COLLECTION_REMOVE_COUNT (ref=" + COLLECTION_REMOVE_COUNT + ") to "
+ stats.getCollectionRemoveCount());
preAssertTrue("COLLECTION_UPDATE_COUNT increased more than 5% (ref=" + COLLECTION_UPDATE_COUNT + "): " + stats.getCollectionUpdateCount(),
stats.getCollectionUpdateCount() <= (COLLECTION_UPDATE_COUNT * 1.05), failedAsserts);
if (stats.getCollectionUpdateCount() < (COLLECTION_UPDATE_COUNT * 0.95))
logger.warn("/!\\ You should update reference value COLLECTION_UPDATE_COUNT (ref=" + COLLECTION_UPDATE_COUNT + ") to "
+ stats.getCollectionUpdateCount());
// Entities statistics
preAssertTrue("ENTITY_FETCH_COUNT increased more than 5% (ref=" + ENTITY_FETCH_COUNT + "): " + stats.getEntityFetchCount(),
stats.getEntityFetchCount() < (ENTITY_FETCH_COUNT * 1.05), failedAsserts);
if (stats.getEntityFetchCount() < (ENTITY_FETCH_COUNT * 0.95))
logger.warn("/!\\ You should update reference value ENTITY_FETCH_COUNT (ref=" + ENTITY_FETCH_COUNT + ") to " + stats.getEntityFetchCount());
preAssertTrue("ENTITY_LOAD_COUNT increased more than 5% (ref=" + ENTITY_LOAD_COUNT + "): " + stats.getEntityLoadCount(),
stats.getEntityLoadCount() <= (ENTITY_LOAD_COUNT * 1.05), failedAsserts);
if (stats.getEntityLoadCount() < (ENTITY_LOAD_COUNT * 0.95))
logger.warn("/!\\ You should update reference value ENTITY_LOAD_COUNT (ref=" + ENTITY_LOAD_COUNT + ") to " + stats.getEntityLoadCount());
preAssertTrue("ENTITY_INSERT_COUNT increased more than 5% (ref=" + ENTITY_INSERT_COUNT + "): " + stats.getEntityInsertCount(),
stats.getEntityInsertCount() <= (ENTITY_INSERT_COUNT * 1.05), failedAsserts);
if (stats.getEntityInsertCount() < (ENTITY_INSERT_COUNT * 0.95))
logger.warn("/!\\ You should update reference value ENTITY_INSERT_COUNT (ref=" + ENTITY_INSERT_COUNT + ") to " + stats.getEntityInsertCount());
// Collections statistics
preAssertTrue("COLLECTION_FETCH_COUNT increased more than 5% (ref=" + COLLECTION_FETCH_COUNT + "): " + stats.getCollectionFetchCount(),
stats.getCollectionFetchCount() <= (COLLECTION_FETCH_COUNT * 1.05), failedAsserts);
if (stats.getCollectionFetchCount() < (COLLECTION_FETCH_COUNT * 0.95))
logger.warn("/!\\ You should update reference value COLLECTION_FETCH_COUNT (ref=" + COLLECTION_FETCH_COUNT + ") to "
+ stats.getCollectionFetchCount());
preAssertTrue("COLLECTION_LOAD_COUNT increased more than 5% (ref=" + COLLECTION_LOAD_COUNT + "): " + stats.getCollectionLoadCount(),
stats.getCollectionLoadCount() <= (COLLECTION_LOAD_COUNT * 1.05), failedAsserts);
if (stats.getCollectionLoadCount() < (COLLECTION_LOAD_COUNT * 0.95))
logger.warn("/!\\ You should update reference value COLLECTION_LOAD_COUNT (ref=" + COLLECTION_LOAD_COUNT + ") to " + stats.getCollectionLoadCount());
preAssertTrue("COLLECTION_RECREATE_COUNT increased more than 5% (ref=" + COLLECTION_RECREATE_COUNT + "): " + stats.getCollectionRecreateCount()
, stats.getCollectionRecreateCount() <= (COLLECTION_RECREATE_COUNT * 1.05), failedAsserts);
if(assertDuration) {
// Time of the slowest query executed.
preAssertTrue("Time of the slowest query executed increased more than 50% (ref=" + QUERY_MAX_TIME_MS + "): " + stats.getQueryExecutionMaxTime()
, stats.getQueryExecutionMaxTime() <= (QUERY_MAX_TIME_MS * 1.50), failedAsserts);
if (stats.getQueryExecutionMaxTime() < (QUERY_MAX_TIME_MS * 0.50))
logger.warn("/!\\ You should update reference value QUERY_MAX_TIME_MS (ref=" + QUERY_MAX_TIME_MS + ") to " + stats.getQueryExecutionMaxTime());
// Check test duration
preAssertTrue("Total duration of the test increased more than 5% (ref=" + DURATION + "): " + duration, duration < (DURATION * 1.05), failedAsserts);
if (duration <= (DURATION * 0.85))
logger.warn("/!\\ You should update reference value DURATION (ref=" + DURATION + ") to " + duration);
}
StringBuffer formattedFailedAsserts = new StringBuffer();
for (AssertionError failedAssert : failedAsserts) {
formattedFailedAsserts.append(failedAssert.getMessage());
formattedFailedAsserts.append("\n");
}
String advice = "Analyse the code with your favorite profiler, then see where performances decrease and optimize the code. If you consider this new value as 'normal' then set a new reference value.";
assertTrue(failedAsserts.size() + " Hibernate stats violations: \n" + formattedFailedAsserts.toString() + advice , failedAsserts.isEmpty());
}
private static void preAssertEquals(String msg, long expected, long actual, List<AssertionError> failedAsserts) {
try {
assertEquals(msg, expected, actual);
} catch (AssertionError e) {
failedAsserts.add(e);
}
}
private static void preAssertTrue(String msg, boolean actual, List<AssertionError> failedAsserts) {
try {
assertTrue(msg, actual);
} catch (AssertionError e) {
failedAsserts.add(e);
}
}
}