blob: f83a5634e1d4ed951793885bee8c1dc6fe8d79be [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You 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.apache.geode.internal.cache.execute.metrics;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static org.apache.geode.internal.cache.execute.metrics.FunctionStatsImpl.functionExecutionExceptionsId;
import static org.apache.geode.internal.cache.execute.metrics.FunctionStatsImpl.functionExecutionsCompletedId;
import static org.apache.geode.internal.cache.execute.metrics.FunctionStatsImpl.functionExecutionsCompletedProcessingTimeId;
import static org.apache.geode.internal.cache.execute.metrics.FunctionStatsImpl.functionExecutionsHasResultCompletedProcessingTimeId;
import static org.apache.geode.internal.cache.execute.metrics.FunctionStatsImpl.functionExecutionsHasResultRunningId;
import static org.apache.geode.internal.cache.execute.metrics.FunctionStatsImpl.functionExecutionsRunningId;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.mockito.quality.Strictness;
import org.apache.geode.Statistics;
public class FunctionStatsImplTest {
private static final String FUNCTION_ID = "functionId";
@Rule
public MockitoRule mockitoRule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
@Mock
private Statistics statistics;
@Mock
private FunctionServiceStats functionServiceStats;
private MeterRegistry meterRegistry;
@Before
public void setUp() {
meterRegistry = new SimpleMeterRegistry();
}
@Test
public void constructor_registersSuccessTimer() {
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats);
assertThat(successTimer())
.as("geode.function.executions timer with tags function=%s, succeeded=true", FUNCTION_ID)
.isNotNull();
assertThat(successTimer().getId().getDescription())
.as("success timer description")
.isEqualTo("Count and total time of successful function executions");
}
@Test
public void constructor_registersFailureTimer() {
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats);
assertThat(failureTimer())
.as("geode.function.executions timer with tags function=%s, succeeded=false", FUNCTION_ID)
.isNotNull();
assertThat(failureTimer().getId().getDescription())
.as("failure timer description")
.isEqualTo("Count and total time of failed function executions");
}
@Test
public void constructor_throws_ifMeterRegistryIsNull() {
Throwable thrown = catchThrowable(
() -> new FunctionStatsImpl(FUNCTION_ID, null, statistics, functionServiceStats));
assertThat(thrown)
.isInstanceOf(NullPointerException.class);
}
@Test
public void endFunctionExecution_incrementsSuccessTimerCount() {
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats);
functionStats.endFunctionExecution(0, false);
assertThat(successTimer().count())
.as("Success timer count")
.isEqualTo(1);
}
@Test
public void endFunctionExecution_incrementsSuccessTimerTotalTime() {
long endTime = 5;
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats, endTime,
false);
long startTime = 0;
functionStats.endFunctionExecution(startTime, false);
long elapsedNanos = endTime - startTime;
assertThat(successTimer().totalTime(NANOSECONDS))
.as("Success timer total time")
.isEqualTo(elapsedNanos);
}
@Test
public void endFunctionExecution_noResult_clockStatsDisabled_incrementsStats() {
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats, 0,
false);
functionStats.endFunctionExecution(0, false);
verify(statistics)
.incInt(functionExecutionsCompletedId(), 1);
verify(statistics)
.incInt(functionExecutionsRunningId(), -1);
verify(statistics, never())
.incLong(eq(functionExecutionsCompletedProcessingTimeId()), anyLong());
verify(statistics, never())
.incInt(eq(functionExecutionsHasResultRunningId()), anyInt());
verify(statistics, never())
.incLong(eq(functionExecutionsHasResultCompletedProcessingTimeId()), anyLong());
}
@Test
public void endFunctionExecution_hasResult_clockStatsDisabled_incrementsStats() {
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats, 0,
false);
functionStats.endFunctionExecution(0, true);
verify(statistics)
.incInt(functionExecutionsCompletedId(), 1);
verify(statistics)
.incInt(functionExecutionsRunningId(), -1);
verify(statistics, never())
.incLong(eq(functionExecutionsCompletedProcessingTimeId()), anyLong());
verify(statistics)
.incInt(functionExecutionsHasResultRunningId(), -1);
verify(statistics, never())
.incLong(eq(functionExecutionsHasResultCompletedProcessingTimeId()), anyLong());
}
@Test
public void endFunctionExecution_noResult_clockStatsEnabled_incrementsStats() {
long endTime = 5;
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats, endTime,
true);
long startTime = 0;
functionStats.endFunctionExecution(startTime, false);
long elapsedNanos = endTime - startTime;
verify(statistics)
.incInt(functionExecutionsCompletedId(), 1);
verify(statistics)
.incInt(functionExecutionsRunningId(), -1);
verify(statistics)
.incLong(functionExecutionsCompletedProcessingTimeId(), elapsedNanos);
verify(statistics, never())
.incInt(eq(functionExecutionsHasResultRunningId()), anyInt());
verify(statistics, never())
.incLong(eq(functionExecutionsHasResultCompletedProcessingTimeId()), anyLong());
}
@Test
public void endFunctionExecution_hasResult_clockStatsEnabled_incrementsStats() {
long endTime = 5;
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats, endTime,
true);
long startTime = 0;
functionStats.endFunctionExecution(startTime, true);
long elapsedNanos = endTime - startTime;
verify(statistics)
.incInt(functionExecutionsCompletedId(), 1);
verify(statistics)
.incInt(functionExecutionsRunningId(), -1);
verify(statistics)
.incLong(functionExecutionsCompletedProcessingTimeId(), elapsedNanos);
verify(statistics)
.incInt(functionExecutionsHasResultRunningId(), -1);
verify(statistics)
.incLong(functionExecutionsHasResultCompletedProcessingTimeId(), elapsedNanos);
}
@Test
public void endFunctionExecution_incrementsAggregateStats() {
long endTime = 5;
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats, endTime,
false);
long startTime = 0;
boolean haveResult = true;
functionStats.endFunctionExecution(startTime, haveResult);
long elapsedNanos = endTime - startTime;
verify(functionServiceStats)
.endFunctionExecutionWithElapsedTime(elapsedNanos, haveResult);
}
@Test
public void endFunctionExecutionWithException_incrementsFailureTimerCount() {
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats);
functionStats.endFunctionExecutionWithException(0, false);
assertThat(failureTimer().count())
.as("Failure timer count")
.isEqualTo(1);
}
@Test
public void endFunctionExecutionWithException_incrementsFailureTimerTotalTime() {
long endTime = 5;
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats, endTime,
false);
long startTime = 0;
functionStats.endFunctionExecutionWithException(startTime, false);
long elapsedNanos = endTime - startTime;
assertThat(failureTimer().totalTime(NANOSECONDS))
.as("Failure timer total time")
.isEqualTo(elapsedNanos);
}
@Test
public void endFunctionExecutionWithException_noResult_incrementsStats() {
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats);
functionStats.endFunctionExecutionWithException(0, false);
verify(statistics)
.incInt(functionExecutionsRunningId(), -1);
verify(statistics)
.incInt(functionExecutionExceptionsId(), 1);
verify(statistics, never())
.incInt(eq(functionExecutionsHasResultRunningId()), anyInt());
}
@Test
public void endFunctionExecutionWithException_hasResult_incrementsStats() {
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats);
functionStats.endFunctionExecutionWithException(0, true);
verify(statistics)
.incInt(functionExecutionsRunningId(), -1);
verify(statistics)
.incInt(functionExecutionExceptionsId(), 1);
verify(statistics)
.incInt(functionExecutionsHasResultRunningId(), -1);
}
@Test
public void endFunctionExecutionWithException_incrementsAggregateStats() {
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats);
boolean haveResult = true;
functionStats.endFunctionExecutionWithException(0, haveResult);
verify(functionServiceStats)
.endFunctionExecutionWithException(haveResult);
}
@Test
public void close_removesSuccessTimer() {
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats);
functionStats.close();
assertThat(successTimer())
.as("geode.function.executions timer with tags function=%s, succeeded=true", FUNCTION_ID)
.isNull();
}
@Test
public void close_removesFailureTimer() {
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats);
functionStats.close();
assertThat(failureTimer())
.as("geode.function.executions timer with tags function=%s, succeeded=false", FUNCTION_ID)
.isNull();
}
@Test
public void close_closesTimers() {
Timer successTimer = mock(Timer.class);
Timer failureTimer = mock(Timer.class);
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, mock(MeterRegistry.class), statistics,
functionServiceStats, 0L, false, successTimer, failureTimer);
functionStats.close();
verify(successTimer).close();
verify(failureTimer).close();
}
@Test
public void close_closesStats() {
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats);
functionStats.close();
verify(statistics).close();
}
@Test
public void isClosed_returnsFalse_ifCloseNotCalled() {
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats);
assertThat(functionStats.isClosed())
.isFalse();
}
@Test
public void isClosed_returnsTrue_ifCloseCalled() {
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statistics, functionServiceStats);
functionStats.close();
assertThat(functionStats.isClosed())
.isTrue();
}
@Test
public void getStatistics_returnsGivenStatistics() {
Statistics statisticsPassedToConstructor = mock(Statistics.class);
FunctionStats functionStats =
new FunctionStatsImpl(FUNCTION_ID, meterRegistry, statisticsPassedToConstructor,
functionServiceStats);
assertThat(functionStats.getStatistics())
.isSameAs(statisticsPassedToConstructor);
}
private Timer successTimer() {
return functionExecutionsTimer(true);
}
private Timer failureTimer() {
return functionExecutionsTimer(false);
}
private Timer functionExecutionsTimer(boolean succeededTagValue) {
return meterRegistry
.find("geode.function.executions")
.tag("function", FUNCTION_ID)
.tag("succeeded", String.valueOf(succeededTagValue))
.timer();
}
}