/* * Copyright Terracotta, Inc. * * 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 org.ehcache.impl.internal.util; import org.ehcache.core.spi.store.Store; import org.hamcrest.Description; import org.hamcrest.Factory; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; import org.junit.Assert; import org.terracotta.context.ContextManager; import org.terracotta.context.TreeNode; import org.terracotta.statistics.OperationStatistic; import org.terracotta.statistics.ValueStatistic; import java.util.Arrays; import java.util.EnumSet; import java.util.List; /** * StatisticsTestUtils */ public class StatisticsTestUtils { /** * Validates expected {@link org.terracotta.statistics.OperationStatistic} updates for the * indicated {@code Ehcache} instance. The statistics identified in {@code changed} are * checked for a value of {@code 1}; all other statistics in the same enumeration class are * checked for a value of {@code 0}. * * @param store the store instance to check * @param changed the statistics values that should have updated values * @param <E> the statistics enumeration type */ public static <E extends Enum<E>> void validateStats(final Store<?, ?> store, final EnumSet<E> changed) { assert changed != null; final EnumSet<E> unchanged = EnumSet.complementOf(changed); @SuppressWarnings("unchecked") final List<EnumSet<E>> sets = Arrays.asList(changed, unchanged); Class<E> statsClass = null; for (final EnumSet<E> set : sets) { if (!set.isEmpty()) { statsClass = set.iterator().next().getDeclaringClass(); break; } } assert statsClass != null; final OperationStatistic<E> operationStatistic = getOperationStatistic(store, statsClass); for (final E statId : changed) { Assert.assertThat(String.format("Value for %s.%s", statId.getDeclaringClass().getName(), statId.name()), getStatistic(operationStatistic, statId), StatisticMatcher.equalTo(1L)); } for (final E statId : unchanged) { Assert.assertThat(String.format("Value for %s.%s", statId.getDeclaringClass().getName(), statId.name()), getStatistic(operationStatistic, statId), StatisticMatcher.equalTo(0L)); } } public static <E extends Enum<E>> void validateStat(final Store<?, ?> store, E outcome, long count) { OperationStatistic<E> operationStatistic = getOperationStatistic(store, outcome.getDeclaringClass()); Assert.assertThat(getStatistic(operationStatistic, outcome), StatisticMatcher.equalTo(count)); } /** * Gets the value of the statistic indicated from an {@link OperationStatistic} * instance. * * @param operationStatistic the {@code OperationStatistic} instance from which the statistic is to * be obtained * @param statId the {@code Enum} constant identifying the statistic for which the value must be obtained * @param <E> The {@code Enum} type for the statistics * * @return the value, possibly null, for {@code statId} about {@code ehcache} */ private static <E extends Enum<E>> Number getStatistic(final OperationStatistic<E> operationStatistic, final E statId) { if (operationStatistic != null) { final ValueStatistic<Long> valueStatistic = operationStatistic.statistic(statId); return (valueStatistic == null ? null : valueStatistic.value()); } return null; } /** * Gets a reference to the {@link OperationStatistic} instance holding the * class of statistics specified for the {@code Ehcache} instance provided. * * @param store the store instance for which the {@code OperationStatistic} instance * should be obtained * @param statsClass the {@code Class} of statistics for which the {@code OperationStatistic} instance * should be obtained * @param <E> the {@code Enum} type for the statistics * * @return a reference to the {@code OperationStatistic} instance holding the {@code statsClass} statistics; * may be {@code null} if {@code statsClass} statistics do not exist for {@code ehcache} */ private static <E extends Enum<E>> OperationStatistic<E> getOperationStatistic(final Store<?, ?> store, final Class<E> statsClass) { for (final TreeNode statNode : ContextManager.nodeFor(store).getChildren()) { final Object statObj = statNode.getContext().attributes().get("this"); if (statObj instanceof OperationStatistic<?>) { @SuppressWarnings("unchecked") final OperationStatistic<E> statistic = (OperationStatistic<E>)statObj; if (statistic.type().equals(statsClass)) { return statistic; } } } return null; } /** * Local {@code org.hamcrest.TypeSafeMatcher} implementation for testing * {@code org.terracotta.statistics.OperationStatistic} values. */ private static final class StatisticMatcher extends TypeSafeMatcher<Number> { final Number expected; private StatisticMatcher(final Class<?> expectedType, final Number expected) { super(expectedType); this.expected = expected; } @Override protected boolean matchesSafely(final Number value) { if (value != null) { return (value.longValue() == this.expected.longValue()); } else { return this.expected.longValue() == 0L; } } @Override public void describeTo(final Description description) { if (this.expected.longValue() == 0L) { description.appendText("zero or null"); } else { description.appendValue(this.expected); } } @Factory public static Matcher<Number> equalTo(final Number expected) { return new StatisticMatcher(Number.class, expected); } } }