/* * Copyright (C) 2015 The Android Open Source Project * * 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.android.builder.profile; import com.android.annotations.NonNull; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import java.util.concurrent.atomic.AtomicBoolean; /** * Tests for the {@link ThreadRecorder} class. */ public class ThreadRecorderTest { @Before public void setUp() { // reset for each test. ProcessRecorderFactory.sINSTANCE = new ProcessRecorderFactory(); ProcessRecorderFactory.sINSTANCE.setRecordWriter( Mockito.mock(ProcessRecorder.ExecutionRecordWriter.class)); } @Test public void testBasicTracing() { Integer value = ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception{ return 10; } }); Assert.assertNotNull(value); Assert.assertEquals(10, value.intValue()); } @Test public void testBasicNoExceptionHandling() { final AtomicBoolean handlerCalled = new AtomicBoolean(false); Integer value = ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception{ return 10; } @Override public void handleException(@NonNull Exception e) { handlerCalled.set(true); } }); Assert.assertNotNull(value); Assert.assertEquals(10, value.intValue()); // exception handler shouldn't have been called. Assert.assertFalse(handlerCalled.get()); } @Test public void testBasicExceptionHandling() { final Exception toBeThrown = new Exception("random"); final AtomicBoolean handlerCalled = new AtomicBoolean(false); Integer value = ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception { throw toBeThrown; } @Override public void handleException(@NonNull Exception e) { handlerCalled.set(true); Assert.assertEquals(toBeThrown, e); } }); Assert.assertTrue(handlerCalled.get()); Assert.assertNull(value); } @Test public void testBlocks() { Integer value = ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception { return ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception { return 10; } }); } }); Assert.assertNotNull(value); Assert.assertEquals(10, value.intValue()); } @Test public void testBlocksWithInnerException() { final Exception toBeThrown = new Exception("random"); final AtomicBoolean handlerCalled = new AtomicBoolean(false); Integer value = ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception { return ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception { throw toBeThrown; } @Override public void handleException(@NonNull Exception e) { handlerCalled.set(true); Assert.assertEquals(toBeThrown, e); } }); } }); Assert.assertTrue(handlerCalled.get()); Assert.assertNull(value); } @Test public void testBlocksWithOuterException() { final Exception toBeThrown = new Exception("random"); final AtomicBoolean handlerCalled = new AtomicBoolean(false); Integer value = ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception { ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception { return 10; } }); throw toBeThrown; } @Override public void handleException(@NonNull Exception e) { handlerCalled.set(true); Assert.assertEquals(toBeThrown, e); } }); Assert.assertTrue(handlerCalled.get()); Assert.assertNull(value); } @Test public void testBlocksWithInnerExceptionRepackaged() { final Exception toBeThrown = new Exception("random"); final AtomicBoolean handlerCalled = new AtomicBoolean(false); Integer value = ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception { return ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception { throw toBeThrown; } }); } @Override public void handleException(@NonNull Exception e) { handlerCalled.set(true); Assert.assertTrue(e instanceof RuntimeException); Assert.assertEquals(toBeThrown, e.getCause()); } }); Assert.assertTrue(handlerCalled.get()); Assert.assertNull(value); } @Test public void testWithMulipleInnerBlocksWithExceptionRepackaged() { final Exception toBeThrown = new Exception("random"); final AtomicBoolean handlerCalled = new AtomicBoolean(false); // make three layers and throw an exception from the bottom layer, ensure the exception // is not repackaged in a RuntimeException several time as it makes its way back up // to the handler. Integer value = ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception { return ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception { return ThreadRecorder.get().record( ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception { throw toBeThrown; } }); } }); } @Override public void handleException(@NonNull Exception e) { handlerCalled.set(true); Assert.assertTrue(e instanceof RuntimeException); Assert.assertEquals(toBeThrown, e.getCause()); } }); Assert.assertTrue(handlerCalled.get()); Assert.assertNull(value); } @Test public void testExceptionPropagation() { final Exception toBeThrown = new Exception("random"); try { ThreadRecorder.get().record(ExecutionType.SOME_RANDOM_PROCESSING, new Recorder.Block<Integer>() { @Override public Integer call() throws Exception { throw toBeThrown; } }); } catch (Exception e) { Assert.assertEquals(toBeThrown, e.getCause()); return; } Assert.fail("Exception not propagated."); } }