/** * 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.apache.aurora.scheduler.storage.db; import java.lang.reflect.Method; import java.util.concurrent.atomic.AtomicLong; import org.apache.aurora.common.stats.SlidingStats; import org.apache.aurora.common.stats.Stats; import org.apache.aurora.common.testing.easymock.EasyMockTest; import org.apache.aurora.common.util.Clock; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.Invocation; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.easymock.PowerMock; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static junit.framework.TestCase.assertNotNull; @RunWith(PowerMockRunner.class) @PrepareForTest({MappedStatement.class, Method.class}) public class InstrumentingInterceptorTest extends EasyMockTest { private InstrumentingInterceptor interceptor; private Invocation invocation; private SlidingStats slidingStats; private Clock mockClock; @Before public void setUp() throws Exception { invocation = createMock(Invocation.class); mockClock = createMock(Clock.class); slidingStats = createMock(SlidingStats.class); interceptor = new InstrumentingInterceptor(mockClock, name -> slidingStats); } private void expectGetArgs(Object[] args, int times) { expect(invocation.getArgs()).andReturn(args).times(times); } @Test public void testStatIsCreatedOnce() throws Throwable { final AtomicLong factoryCallCount = new AtomicLong(0); interceptor = new InstrumentingInterceptor(mockClock, name -> { factoryCallCount.incrementAndGet(); return slidingStats; }); String statName = "test"; MappedStatement fakeMappedStatement = createMock(MappedStatement.class); Object[] args = new Object[] {fakeMappedStatement}; expect(mockClock.nowNanos()).andReturn(0L).andReturn(1000L); expectGetArgs(args, 3); expect(fakeMappedStatement.getId()).andReturn(statName); expect(invocation.proceed()).andReturn("result"); slidingStats.accumulate(1000); expectLastCall(); expect(mockClock.nowNanos()).andReturn(0L).andReturn(1000L); expectGetArgs(args, 3); expect(fakeMappedStatement.getId()).andReturn(statName); expect(invocation.proceed()).andReturn("result"); slidingStats.accumulate(1000); expectLastCall(); control.replay(); // Perform the test interceptor.intercept(invocation); assertEquals(1L, factoryCallCount.get()); interceptor.intercept(invocation); assertEquals(1L, factoryCallCount.get()); } @Test public void testInterceptMarksMetrics() throws Throwable { MappedStatement fakeMappedStatement = createMock(MappedStatement.class); Object[] args = new Object[] {fakeMappedStatement}; expect(mockClock.nowNanos()).andReturn(0L).andReturn(1000L); expectGetArgs(args, 3); expect(fakeMappedStatement.getId()).andReturn("test"); expect(invocation.proceed()).andReturn("result"); slidingStats.accumulate(1000); expectLastCall(); control.replay(); // Perform the test Object res = interceptor.intercept(invocation); assertEquals("result", res); } @Test public void testInterceptNotAMappedStatement() throws Throwable { interceptor = new InstrumentingInterceptor(mockClock); Method mockMethod = PowerMock.createMock(Method.class); Object notAMappedStatement = new Object(); Object[] args = new Object[] {notAMappedStatement}; expect(mockClock.nowNanos()).andReturn(0L).andReturn(1000L); expectGetArgs(args, 2); expect(invocation.getMethod()).andReturn(mockMethod); expect(invocation.getTarget()).andReturn("test"); expect(invocation.proceed()).andReturn(null); control.replay(); assertNull(Stats.getVariable("mybatis.invalid_invocations_nanos_total")); assertNull(Stats.getVariable("mybatis.invalid_invocations_nanos_total_per_sec")); assertNull(Stats.getVariable("mybatis.invalid_invocations_events")); assertNull(Stats.getVariable("mybatis.invalid_invocations_nanos_per_event")); assertNull(Stats.getVariable("mybatis.invalid_invocations_events_per_sec")); interceptor.intercept(invocation); // upon interception of invocation that does not have a valid MappedStatement use // invalid_invocations as the name assertNotNull(Stats.getVariable("mybatis.invalid_invocations_nanos_total")); assertNotNull(Stats.getVariable("mybatis.invalid_invocations_nanos_total_per_sec")); assertNotNull(Stats.getVariable("mybatis.invalid_invocations_events")); assertNotNull(Stats.getVariable("mybatis.invalid_invocations_nanos_per_event")); assertNotNull(Stats.getVariable("mybatis.invalid_invocations_events_per_sec")); assertEquals(1000L, Stats.getVariable("mybatis.invalid_invocations_nanos_total").read()); assertEquals(1L, Stats.getVariable("mybatis.invalid_invocations_events").read()); } }