Merge "Resolve dynamic File in maps"
diff --git a/src/com/android/tradefed/device/metric/BaseDeviceMetricCollector.java b/src/com/android/tradefed/device/metric/BaseDeviceMetricCollector.java
index 36590f8..56faee7 100644
--- a/src/com/android/tradefed/device/metric/BaseDeviceMetricCollector.java
+++ b/src/com/android/tradefed/device/metric/BaseDeviceMetricCollector.java
@@ -115,6 +115,11 @@
     }
 
     @Override
+    public void onTestFail(DeviceMetricData testData, TestDescription test) {
+        // Does nothing
+    }
+
+    @Override
     public void onTestEnd(
             DeviceMetricData testData, final Map<String, Metric> currentTestCaseMetrics) {
         // Does nothing
@@ -201,6 +206,15 @@
 
     @Override
     public final void testFailed(TestDescription test, String trace) {
+        mSkipTestCase = shouldSkip(test);
+        if (!mSkipTestCase) {
+            try {
+                onTestFail(mTestData, test);
+            } catch (Throwable t) {
+                // Prevent exception from messing up the status reporting.
+                CLog.e(t);
+            }
+        }
         mForwarder.testFailed(test, trace);
     }
 
diff --git a/src/com/android/tradefed/device/metric/IMetricCollector.java b/src/com/android/tradefed/device/metric/IMetricCollector.java
index 88272e3..feb1a59 100644
--- a/src/com/android/tradefed/device/metric/IMetricCollector.java
+++ b/src/com/android/tradefed/device/metric/IMetricCollector.java
@@ -88,6 +88,14 @@
     public void onTestStart(DeviceMetricData testData);
 
     /**
+     * Callback when a test case fails.
+     *
+     * @param testData the {@link DeviceMetricData} holding the data for the test case.
+     * @param test the {@link TestDescription} of the test case in progress.
+     */
+    public void onTestFail(DeviceMetricData testData, TestDescription test);
+
+    /**
      * Callback when a test case is ended. This should be the time for clean up.
      *
      * @param testData the {@link DeviceMetricData} holding the data for the test case. Will be the
diff --git a/src/com/android/tradefed/device/metric/ScreenshotOnFailureCollector.java b/src/com/android/tradefed/device/metric/ScreenshotOnFailureCollector.java
new file mode 100644
index 0000000..b493109
--- /dev/null
+++ b/src/com/android/tradefed/device/metric/ScreenshotOnFailureCollector.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 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.tradefed.device.metric;
+
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.InputStreamSource;
+import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.TestDescription;
+import com.android.tradefed.util.StreamUtil;
+
+/** Collector that will capture and log a screenshot when a test case fails. */
+public class ScreenshotOnFailureCollector extends BaseDeviceMetricCollector {
+
+    @Override
+    public void onTestFail(DeviceMetricData testData, TestDescription test) {
+        for (ITestDevice device : getDevices()) {
+            try {
+                InputStreamSource screenSource = device.getScreenshot();
+                super.testLog(
+                        String.format("screenshot-%s_%s", test.getClassName(), test.getTestName()),
+                        LogDataType.PNG,
+                        screenSource);
+                StreamUtil.cancel(screenSource);
+            } catch (DeviceNotAvailableException e) {
+                CLog.e(
+                        "Device %s became unavailable while capturing screenshot, %s",
+                        device.getSerialNumber(), e.toString());
+            }
+        }
+    }
+}
diff --git a/tests/src/com/android/tradefed/UnitTests.java b/tests/src/com/android/tradefed/UnitTests.java
index 6ea3398..5cdb516 100644
--- a/tests/src/com/android/tradefed/UnitTests.java
+++ b/tests/src/com/android/tradefed/UnitTests.java
@@ -94,6 +94,7 @@
 import com.android.tradefed.device.metric.ProcessMaxMemoryCollectorTest;
 import com.android.tradefed.device.metric.ScheduleMultipleDeviceMetricCollectorTest;
 import com.android.tradefed.device.metric.ScheduledDeviceMetricCollectorTest;
+import com.android.tradefed.device.metric.ScreenshotOnFailureCollectorTest;
 import com.android.tradefed.device.metric.TemperatureCollectorTest;
 import com.android.tradefed.device.metric.TraceMetricCollectorTest;
 import com.android.tradefed.device.recovery.BatteryUnavailableDeviceRecoveryTest;
@@ -434,6 +435,7 @@
     ProcessMaxMemoryCollectorTest.class,
     ScheduledDeviceMetricCollectorTest.class,
     ScheduleMultipleDeviceMetricCollectorTest.class,
+    ScreenshotOnFailureCollectorTest.class,
     TemperatureCollectorTest.class,
     TraceMetricCollectorTest.class,
 
diff --git a/tests/src/com/android/tradefed/device/DeviceManagerTest.java b/tests/src/com/android/tradefed/device/DeviceManagerTest.java
index acd7ba8..e51dd25 100644
--- a/tests/src/com/android/tradefed/device/DeviceManagerTest.java
+++ b/tests/src/com/android/tradefed/device/DeviceManagerTest.java
@@ -16,6 +16,13 @@
 
 package com.android.tradefed.device;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
 import com.android.ddmlib.IDevice;
 import com.android.ddmlib.IDevice.DeviceState;
@@ -30,11 +37,13 @@
 import com.android.tradefed.util.IRunUtil;
 import com.android.tradefed.util.RunUtil;
 
-import junit.framework.TestCase;
-
 import org.easymock.Capture;
 import org.easymock.EasyMock;
 import org.easymock.IAnswer;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 
 import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
@@ -44,10 +53,9 @@
 import java.util.List;
 import java.util.concurrent.Semaphore;
 
-/**
- * Unit tests for {@link DeviceManager}.
- */
-public class DeviceManagerTest extends TestCase {
+/** Unit tests for {@link DeviceManager}. */
+@RunWith(JUnit4.class)
+public class DeviceManagerTest {
 
     private static final String DEVICE_SERIAL = "serial";
     private static final String MAC_ADDRESS = "FF:FF:FF:FF:FF:FF";
@@ -121,12 +129,8 @@
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mMockAdbBridge = EasyMock.createNiceMock(IAndroidDebugBridge.class);
         mMockAdbBridge.addDeviceChangeListener((IDeviceChangeListener) EasyMock.anyObject());
         EasyMock.expectLastCall()
@@ -289,6 +293,7 @@
      * Test @link DeviceManager#allocateDevice()} when a IDevice is present on DeviceManager
      * creation.
      */
+    @Test
     public void testAllocateDevice() {
         setCheckAvailableDeviceExpectations();
         EasyMock.expect(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
@@ -303,6 +308,7 @@
     /**
      * Test {@link DeviceManager#allocateDevice(IDeviceSelection, boolean)} when device is returned.
      */
+    @Test
     public void testAllocateDevice_match() {
         mDeviceSelections.addSerial(DEVICE_SERIAL);
         setCheckAvailableDeviceExpectations();
@@ -317,6 +323,7 @@
     /**
      * Test that when allocating a fake device we create a placeholder then delete it at the end.
      */
+    @Test
     public void testAllocateDevice_match_temporary() {
         mDeviceSelections.setNullDeviceRequested(true);
         mDeviceSelections.addSerial(DEVICE_SERIAL);
@@ -353,8 +360,9 @@
 
     /**
      * Test {@link DeviceManager#allocateDevice(IDeviceSelection, boolean)} when stub emulator is
-     * requested
+     * requested.
      */
+    @Test
     public void testAllocateDevice_stubEmulator() {
         mDeviceSelections.setStubEmulatorRequested(true);
         EasyMock.expect(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_AVAILABLE))
@@ -370,9 +378,8 @@
         verifyMocks();
     }
 
-    /**
-     * Test freeing an emulator
-     */
+    /** Test freeing an emulator */
+    @Test
     public void testFreeDevice_emulator() {
         mDeviceSelections.setStubEmulatorRequested(true);
         EasyMock.expect(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_AVAILABLE))
@@ -408,6 +415,7 @@
      * Test {@link DeviceManager#allocateDevice(IDeviceSelection, boolean)} when a null device is
      * requested.
      */
+    @Test
     public void testAllocateDevice_nullDevice() {
         mDeviceSelections.setNullDeviceRequested(true);
         EasyMock.expect(mMockIDevice.isEmulator()).andStubReturn(Boolean.FALSE);
@@ -429,6 +437,7 @@
      * Test that DeviceManager will add devices on fastboot to available queue on startup, and that
      * they can be allocated.
      */
+    @Test
     public void testAllocateDevice_fastboot() {
         EasyMock.reset(mMockRunUtil);
         // mock 'fastboot help' call
@@ -455,9 +464,8 @@
         verifyMocks();
     }
 
-    /**
-     * Test {@link DeviceManager#forceAllocateDevice(String)} when device is unknown
-     */
+    /** Test {@link DeviceManager#forceAllocateDevice(String)} when device is unknown */
+    @Test
     public void testForceAllocateDevice() {
         EasyMock.expect(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_ALLOCATE_REQUEST))
                 .andReturn(new DeviceEventResponse(DeviceAllocationState.Allocated, true));
@@ -467,9 +475,8 @@
         verifyMocks();
     }
 
-    /**
-     * Test {@link DeviceManager#forceAllocateDevice(String)} when device is available
-     */
+    /** Test {@link DeviceManager#forceAllocateDevice(String)} when device is available */
+    @Test
     public void testForceAllocateDevice_available() {
         setCheckAvailableDeviceExpectations();
         EasyMock.expect(mMockTestDevice.getAllocationState())
@@ -482,9 +489,8 @@
         verifyMocks();
     }
 
-    /**
-     * Test {@link DeviceManager#forceAllocateDevice(String)} when device is already allocated
-     */
+    /** Test {@link DeviceManager#forceAllocateDevice(String)} when device is already allocated */
+    @Test
     public void testForceAllocateDevice_alreadyAllocated() {
         setCheckAvailableDeviceExpectations();
         EasyMock.expect(mMockTestDevice.getAllocationState())
@@ -500,9 +506,8 @@
         verifyMocks();
     }
 
-    /**
-     * Test method for {@link DeviceManager#freeDevice(ITestDevice, FreeDeviceState)}.
-     */
+    /** Test method for {@link DeviceManager#freeDevice(ITestDevice, FreeDeviceState)}. */
+    @Test
     public void testFreeDevice() {
         setCheckAvailableDeviceExpectations();
         EasyMock.expect(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
@@ -519,9 +524,10 @@
     }
 
     /**
-     * Verified that {@link DeviceManager#freeDevice(ITestDevice, FreeDeviceState)}
-     * ignores a call with a device that has not been allocated.
+     * Verified that {@link DeviceManager#freeDevice(ITestDevice, FreeDeviceState)} ignores a call
+     * with a device that has not been allocated.
      */
+    @Test
     public void testFreeDevice_noop() {
         setCheckAvailableDeviceExpectations();
         IManagedTestDevice testDevice = EasyMock.createNiceMock(IManagedTestDevice.class);
@@ -539,6 +545,7 @@
      * Verified that {@link DeviceManager} calls {@link IManagedTestDevice#setIDevice(IDevice)} when
      * DDMS allocates a new IDevice on connection.
      */
+    @Test
     public void testSetIDevice() {
         setCheckAvailableDeviceExpectations();
         EasyMock.expect(mMockTestDevice.getAllocationState())
@@ -569,6 +576,7 @@
      * Test {@link DeviceManager#allocateDevice()} when {@link DeviceManager#init()} has not been
      * called.
      */
+    @Test
     public void testAllocateDevice_noInit() {
         try {
             createDeviceManagerNoInit().allocateDevice(mDeviceSelections);
@@ -578,10 +586,8 @@
         }
     }
 
-    /**
-     * Test {@link DeviceManager#init(IDeviceSelection, List)}
-     * with a global exclusion filter
-     */
+    /** Test {@link DeviceManager#init(IDeviceSelection, List)} with a global exclusion filter */
+    @Test
     public void testInit_excludeDevice() throws Exception {
         EasyMock.expect(mMockIDevice.getState()).andReturn(DeviceState.ONLINE);
         mMockTestDevice.setDeviceState(TestDeviceState.ONLINE);
@@ -605,9 +611,8 @@
         verifyMocks();
     }
 
-    /**
-     * Test {@link DeviceManager#init(IDeviceSelection, List)} with a global inclusion filter
-     */
+    /** Test {@link DeviceManager#init(IDeviceSelection, List)} with a global inclusion filter */
+    @Test
     public void testInit_includeDevice() throws Exception {
         IDevice excludedDevice = EasyMock.createMock(IDevice.class);
         EasyMock.expect(excludedDevice.getSerialNumber()).andStubReturn("excluded");
@@ -634,9 +639,8 @@
         verifyMocks(excludedDevice);
     }
 
-    /**
-     * Verified that a disconnected device state gets updated
-     */
+    /** Verified that a disconnected device state gets updated */
+    @Test
     public void testSetState_disconnected() {
         setCheckAvailableDeviceExpectations();
         EasyMock.expect(mMockTestDevice.handleAllocationEvent(DeviceEvent.ALLOCATE_REQUEST))
@@ -651,9 +655,8 @@
         verifyMocks();
     }
 
-    /**
-     * Verified that a offline device state gets updated
-     */
+    /** Verified that a offline device state gets updated */
+    @Test
     public void testSetState_offline() {
         setCheckAvailableDeviceExpectations();
         EasyMock.expect(mMockTestDevice.getAllocationState())
@@ -676,9 +679,8 @@
 
     // TODO: add test for fastboot state changes
 
-    /**
-     * Test normal success case for {@link DeviceManager#connectToTcpDevice(String)}
-     */
+    /** Test normal success case for {@link DeviceManager#connectToTcpDevice(String)} */
+    @Test
     public void testConnectToTcpDevice() throws Exception {
         final String ipAndPort = "ip:5555";
         setConnectToTcpDeviceExpectations(ipAndPort);
@@ -694,6 +696,7 @@
      * Test a {@link DeviceManager#connectToTcpDevice(String)} call where device is already
      * allocated
      */
+    @Test
     public void testConnectToTcpDevice_alreadyAllocated() throws Exception {
         final String ipAndPort = "ip:5555";
         setConnectToTcpDeviceExpectations(ipAndPort);
@@ -711,9 +714,8 @@
         verifyMocks();
     }
 
-    /**
-     * Test {@link DeviceManager#connectToTcpDevice(String)} where device does not appear on adb
-     */
+    /** Test {@link DeviceManager#connectToTcpDevice(String)} where device does not appear on adb */
+    @Test
     public void testConnectToTcpDevice_notOnline() throws Exception {
         final String ipAndPort = "ip:5555";
         setConnectToTcpDeviceExpectations(ipAndPort);
@@ -730,9 +732,8 @@
         verifyMocks();
     }
 
-    /**
-     * Test {@link DeviceManager#connectToTcpDevice(String)} where the 'adb connect' call fails.
-     */
+    /** Test {@link DeviceManager#connectToTcpDevice(String)} where the 'adb connect' call fails. */
+    @Test
     public void testConnectToTcpDevice_connectFailed() throws Exception {
         final String ipAndPort = "ip:5555";
 
@@ -759,9 +760,8 @@
         verifyMocks();
     }
 
-    /**
-     * Test normal success case for {@link DeviceManager#disconnectFromTcpDevice(ITestDevice)}
-     */
+    /** Test normal success case for {@link DeviceManager#disconnectFromTcpDevice(ITestDevice)} */
+    @Test
     public void testDisconnectFromTcpDevice() throws Exception {
         final String ipAndPort = "ip:5555";
         EasyMock.expect(mMockTestDevice.handleAllocationEvent(DeviceEvent.FREE_UNKNOWN)).andReturn(
@@ -779,9 +779,8 @@
         verifyMocks();
     }
 
-    /**
-     * Test normal success case for {@link DeviceManager#reconnectDeviceToTcp(ITestDevice)}.
-     */
+    /** Test normal success case for {@link DeviceManager#reconnectDeviceToTcp(ITestDevice)}. */
+    @Test
     public void testReconnectDeviceToTcp() throws Exception {
         final String ipAndPort = "ip:5555";
         // use the mMockTestDevice as the initially connected to usb device
@@ -802,6 +801,7 @@
      * Test {@link DeviceManager#reconnectDeviceToTcp(ITestDevice)} when tcp connected device does
      * not come online.
      */
+    @Test
     public void testReconnectDeviceToTcp_notOnline() throws Exception {
         final String ipAndPort = "ip:5555";
         // use the mMockTestDevice as the initially connected to usb device
@@ -826,9 +826,8 @@
         verifyMocks();
     }
 
-    /**
-     * Basic test for {@link DeviceManager#sortDeviceList(List)}
-     */
+    /** Basic test for {@link DeviceManager#sortDeviceList(List)} */
+    @Test
     public void testSortDeviceList() {
         DeviceDescriptor availDevice1 = createDeviceDesc("aaa", DeviceAllocationState.Available);
         DeviceDescriptor availDevice2 = createDeviceDesc("bbb", DeviceAllocationState.Available);
@@ -916,9 +915,8 @@
                 .andReturn(new DeviceEventResponse(DeviceAllocationState.Available, true));
     }
 
-    /**
-     * Test freeing a tcp device, it must return to an unavailable status
-     */
+    /** Test freeing a tcp device, it must return to an unavailable status */
+    @Test
     public void testFreeDevice_tcpDevice() {
         mDeviceSelections.setTcpDeviceRequested(true);
         EasyMock.expect(mMockTestDevice.handleAllocationEvent(DeviceEvent.FORCE_AVAILABLE))
@@ -955,6 +953,7 @@
      * Test freeing a device that was unable but showing in adb devices. Device will become
      * Unavailable but still seen by the DeviceManager.
      */
+    @Test
     public void testFreeDevice_unavailable() {
         EasyMock.expect(mMockIDevice.isEmulator()).andStubReturn(Boolean.FALSE);
         EasyMock.expect(mMockIDevice.getState()).andReturn(DeviceState.ONLINE);
@@ -1018,6 +1017,7 @@
      * Test that when freeing an Unavailable device that is not in 'adb devices' we correctly remove
      * it from our tracking list.
      */
+    @Test
     public void testFreeDevice_unknown() {
         EasyMock.expect(mMockIDevice.isEmulator()).andStubReturn(Boolean.FALSE);
         EasyMock.expect(mMockIDevice.getState()).andReturn(DeviceState.ONLINE);
@@ -1082,6 +1082,7 @@
      * Test that when freeing an Unavailable device that is not in 'adb devices' we correctly remove
      * it from our tracking list even if its serial is a substring of another serial.
      */
+    @Test
     public void testFreeDevice_unknown_subName() {
         EasyMock.expect(mMockIDevice.isEmulator()).andStubReturn(Boolean.FALSE);
         EasyMock.expect(mMockIDevice.getState()).andReturn(DeviceState.ONLINE);
@@ -1165,9 +1166,8 @@
         EasyMock.expect(mMockTestDevice.getDeviceDescriptor()).andReturn(descriptor);
     }
 
-    /**
-     * Test that {@link DeviceManager#listAllDevices()} returns a list with all devices.
-     */
+    /** Test that {@link DeviceManager#listAllDevices()} returns a list with all devices. */
+    @Test
     public void testListAllDevices() throws Exception {
         setCheckAvailableDeviceExpectations();
         setDeviceDescriptorExpectation();
@@ -1186,6 +1186,7 @@
      * Test {@link DeviceManager#getDeviceDescriptor(String)} returns the device with the given
      * serial.
      */
+    @Test
     public void testGetDeviceDescriptor() throws Exception {
         setCheckAvailableDeviceExpectations();
         setDeviceDescriptorExpectation();
@@ -1203,6 +1204,7 @@
      * Test that {@link DeviceManager#getDeviceDescriptor(String)} returns null if there are no
      * devices with the given serial.
      */
+    @Test
     public void testGetDeviceDescriptor_noMatch() throws Exception {
         setCheckAvailableDeviceExpectations();
         replayMocks();
@@ -1216,6 +1218,7 @@
      * Test that {@link DeviceManager#displayDevicesInfo(PrintWriter, boolean)} properly print out
      * the device info.
      */
+    @Test
     public void testDisplayDevicesInfo() throws Exception {
         setCheckAvailableDeviceExpectations();
         setDeviceDescriptorExpectation();
@@ -1235,6 +1238,7 @@
      * Test that {@link DeviceManager#shouldAdbBridgeBeRestarted()} properly reports the flag state
      * based on if it was requested or not.
      */
+    @Test
     public void testAdbBridgeFlag() throws Exception {
         setCheckAvailableDeviceExpectations();
         replayMocks();
@@ -1253,6 +1257,7 @@
      * Test that when a {@link IDeviceMonitor} is available in {@link DeviceManager} it properly
      * goes through its life cycle.
      */
+    @Test
     public void testDeviceMonitorLifeCycle() throws Exception {
         IDeviceMonitor mockMonitor = EasyMock.createMock(IDeviceMonitor.class);
         List<IDeviceMonitor> monitors = new ArrayList<>();
@@ -1270,6 +1275,7 @@
     }
 
     /** Ensure that restarting adb bridge doesn't restart {@link IDeviceMonitor}. */
+    @Test
     public void testDeviceMonitorLifeCycleWhenAdbRestarts() throws Exception {
         IDeviceMonitor mockMonitor = EasyMock.createMock(IDeviceMonitor.class);
         List<IDeviceMonitor> monitors = new ArrayList<>();
@@ -1289,6 +1295,7 @@
     }
 
     /** Ensure that the flasher instance limiting machinery is working as expected. */
+    @Test
     public void testFlashLimit() throws Exception {
         setCheckAvailableDeviceExpectations();
         replayMocks();
@@ -1310,12 +1317,12 @@
             assertFalse(manager.getConcurrentFlashLock().hasQueuedThreads());
 
             waiter.start();
-            RunUtil.getDefault().sleep(100);  // Thread start should take <100ms
+            RunUtil.getDefault().sleep(200); // Thread start should take <200ms
             assertTrue("Invalid state: waiter thread is not alive", waiter.isAlive());
             assertTrue("No queued threads", manager.getConcurrentFlashLock().hasQueuedThreads());
 
             manager.returnFlashingPermit();
-            RunUtil.getDefault().sleep(100);  // Thread start should take <100ms
+            RunUtil.getDefault().sleep(200); // Thread start should take <200ms
             assertFalse("Unexpected queued threads",
                     manager.getConcurrentFlashLock().hasQueuedThreads());
 
@@ -1328,6 +1335,7 @@
     }
 
     /** Ensure that the flasher limiting respects {@link IHostOptions}. */
+    @Test
     public void testFlashLimit_withHostOptions() throws Exception {
         setCheckAvailableDeviceExpectations();
         replayMocks();
@@ -1366,6 +1374,7 @@
     }
 
     /** Ensure that the flasher instance limiting machinery is working as expected. */
+    @Test
     public void testUnlimitedFlashLimit() throws Exception {
         setCheckAvailableDeviceExpectations();
         replayMocks();
diff --git a/tests/src/com/android/tradefed/device/metric/ScreenshotOnFailureCollectorTest.java b/tests/src/com/android/tradefed/device/metric/ScreenshotOnFailureCollectorTest.java
new file mode 100644
index 0000000..03d2f04
--- /dev/null
+++ b/tests/src/com/android/tradefed/device/metric/ScreenshotOnFailureCollectorTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 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.tradefed.device.metric;
+
+import com.android.tradefed.config.ConfigurationDef;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.IInvocationContext;
+import com.android.tradefed.invoker.InvocationContext;
+import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
+import com.android.tradefed.result.ByteArrayInputStreamSource;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.result.LogDataType;
+import com.android.tradefed.result.TestDescription;
+
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.HashMap;
+
+/** Unit tests for {@link ScreenshotOnFailureCollector}. */
+@RunWith(JUnit4.class)
+public class ScreenshotOnFailureCollectorTest {
+    private ScreenshotOnFailureCollector mCollector;
+    private ITestInvocationListener mMockListener;
+    private ITestDevice mMockDevice;
+
+    private ITestInvocationListener mTestListener;
+    private IInvocationContext mContext;
+
+    @Before
+    public void setUp() {
+        mMockDevice = EasyMock.createMock(ITestDevice.class);
+        mMockListener = EasyMock.createMock(ITestInvocationListener.class);
+        mCollector = new ScreenshotOnFailureCollector();
+        mContext = new InvocationContext();
+        mContext.addAllocatedDevice(ConfigurationDef.DEFAULT_DEVICE_NAME, mMockDevice);
+        mTestListener = mCollector.init(mContext, mMockListener);
+    }
+
+    @Test
+    public void testCollect() throws Exception {
+        TestDescription test = new TestDescription("class", "test");
+        mMockListener.testStarted(EasyMock.eq(test), EasyMock.anyLong());
+        mMockListener.testFailed(EasyMock.eq(test), EasyMock.anyObject());
+        mMockListener.testEnded(
+                EasyMock.eq(test),
+                EasyMock.anyLong(),
+                EasyMock.<HashMap<String, Metric>>anyObject());
+
+        EasyMock.expect(mMockDevice.getScreenshot())
+                .andReturn(new ByteArrayInputStreamSource("".getBytes()));
+        mMockListener.testLog(
+                EasyMock.eq("screenshot-class_test"),
+                EasyMock.eq(LogDataType.PNG),
+                EasyMock.anyObject());
+
+        EasyMock.replay(mMockListener, mMockDevice);
+        mTestListener.testStarted(test);
+        mTestListener.testFailed(test, "I failed");
+        mTestListener.testEnded(test, new HashMap<String, Metric>());
+        EasyMock.verify(mMockListener, mMockDevice);
+    }
+}
diff --git a/tests/src/com/android/tradefed/invoker/TestInvocationTest.java b/tests/src/com/android/tradefed/invoker/TestInvocationTest.java
index c2b46c0..06ba6e7 100644
--- a/tests/src/com/android/tradefed/invoker/TestInvocationTest.java
+++ b/tests/src/com/android/tradefed/invoker/TestInvocationTest.java
@@ -15,6 +15,10 @@
  */
 package com.android.tradefed.invoker;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import com.android.ddmlib.IDevice;
 import com.android.tradefed.build.BuildInfo;
 import com.android.tradefed.build.BuildInfoKey.BuildInfoFileKey;
@@ -35,6 +39,7 @@
 import com.android.tradefed.config.IConfiguration;
 import com.android.tradefed.config.IConfigurationFactory;
 import com.android.tradefed.config.IDeviceConfiguration;
+import com.android.tradefed.config.IGlobalConfiguration;
 import com.android.tradefed.config.Option;
 import com.android.tradefed.config.OptionSetter;
 import com.android.tradefed.device.DeviceAllocationState;
@@ -82,12 +87,14 @@
 import com.android.tradefed.testtype.StubTest;
 import com.android.tradefed.util.FileUtil;
 import com.android.tradefed.util.SystemUtil.EnvVariable;
-
-import junit.framework.Test;
-import junit.framework.TestCase;
+import com.android.tradefed.util.keystore.StubKeyStoreFactory;
 
 import org.easymock.Capture;
 import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 import org.mockito.Mockito;
 
 import java.io.File;
@@ -104,7 +111,8 @@
 
 /** Unit tests for {@link TestInvocation}. */
 @SuppressWarnings("MustBeClosedChecker")
-public class TestInvocationTest extends TestCase {
+@RunWith(JUnit4.class)
+public class TestInvocationTest {
 
     private static final String SERIAL = "serial";
     private static final Map<String, String> EMPTY_MAP = Collections.emptyMap();
@@ -126,6 +134,7 @@
 
     private IConfiguration mStubConfiguration;
     private IConfiguration mStubMultiConfiguration;
+    private IGlobalConfiguration mGlobalConfiguration;
 
     private IInvocationContext mStubInvocationMetadata;
 
@@ -145,13 +154,14 @@
     private IRescheduler mockRescheduler;
     private DeviceDescriptor mFakeDescriptor;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
 
         mStubConfiguration = new Configuration("foo", "bar");
         mStubMultiConfiguration = new Configuration("foo", "bar");
 
+        mGlobalConfiguration = EasyMock.createMock(IGlobalConfiguration.class);
+
         mMockDevice = EasyMock.createMock(ITestDevice.class);
         mMockRecovery = EasyMock.createMock(IDeviceRecovery.class);
         mMockPreparer = EasyMock.createMock(ITargetPreparer.class);
@@ -242,7 +252,12 @@
                         return new InvocationExecution() {
                             @Override
                             protected IShardHelper createShardHelper() {
-                                return new ShardHelper();
+                                return new ShardHelper() {
+                                    @Override
+                                    protected IGlobalConfiguration getGlobalConfiguration() {
+                                        return mGlobalConfiguration;
+                                    }
+                                };
                             }
                         };
                     }
@@ -260,17 +275,12 @@
                 };
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-      super.tearDown();
-
-    }
-
     /**
      * Test the normal case invoke scenario with a {@link IRemoteTest}.
-     * <p/>
-     * Verifies that all external interfaces get notified as expected.
+     *
+     * <p>Verifies that all external interfaces get notified as expected.
      */
+    @Test
     public void testInvoke_RemoteTest() throws Throwable {
         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
         setupMockSuccessListeners();
@@ -285,9 +295,10 @@
 
     /**
      * Test the normal case for multi invoke scenario with a {@link IRemoteTest}.
-     * <p/>
-     * Verifies that all external interfaces get notified as expected.
+     *
+     * <p>Verifies that all external interfaces get notified as expected.
      */
+    @Test
     public void testInvokeMulti_RemoteTest() throws Throwable {
         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
         setupMockSuccessListeners();
@@ -301,11 +312,12 @@
     }
 
     /**
-     * Test the normal case invoke scenario with an {@link ITestSummaryListener} masquerading as
-     * an {@link ITestInvocationListener}.
-     * <p/>
-     * Verifies that all external interfaces get notified as expected.
+     * Test the normal case invoke scenario with an {@link ITestSummaryListener} masquerading as an
+     * {@link ITestInvocationListener}.
+     *
+     * <p>Verifies that all external interfaces get notified as expected.
      */
+    @Test
     public void testInvoke_twoSummary() throws Throwable {
 
         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
@@ -321,10 +333,11 @@
 
     /**
      * Test the invoke scenario where build retrieve fails.
-     * <p/>
-     * An invocation will be started in this scenario.
+     *
+     * <p>An invocation will be started in this scenario.
      */
-    public void testInvoke_buildFailed() throws Throwable  {
+    @Test
+    public void testInvoke_buildFailed() throws Throwable {
         BuildRetrievalError exception = new BuildRetrievalError("error", null, mMockBuildInfo);
         EasyMock.expect(mMockBuildProvider.getBuild()).andThrow(exception);
         EasyMock.expect(mMockBuildInfo.getTestTag()).andStubReturn(null);
@@ -353,10 +366,9 @@
         assertEquals(expectedTestTag, mStubInvocationMetadata.getTestTag());
     }
 
-    /**
-     * Test the invoke scenario where there is no build to test.
-     */
-    public void testInvoke_noBuild() throws Throwable  {
+    /** Test the invoke scenario where there is no build to test. */
+    @Test
+    public void testInvoke_noBuild() throws Throwable {
         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(null);
         setupInvoke();
         setupMockFailureListenersAny(new BuildRetrievalError("No build found to test."), true);
@@ -381,10 +393,9 @@
         stubBuild.cleanUp();
     }
 
-    /**
-     * Test the invoke scenario where there is no build to test for a {@link IRetriableTest}.
-     */
-    public void testInvoke_noBuildRetry() throws Throwable  {
+    /** Test the invoke scenario where there is no build to test for a {@link IRetriableTest}. */
+    @Test
+    public void testInvoke_noBuildRetry() throws Throwable {
         EasyMock.expect(mMockBuildProvider.getBuild()).andReturn(null);
 
         IRetriableTest test = EasyMock.createMock(IRetriableTest.class);
@@ -420,9 +431,9 @@
 
     /**
      * Test the{@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
-     * ITestInvocationListener[])} scenario
-     * where the test is a {@link IDeviceTest}
+     * ITestInvocationListener[])} scenario where the test is a {@link IDeviceTest}
      */
+    @Test
     public void testInvoke_deviceTest() throws Throwable {
          DeviceConfigTest mockDeviceTest = EasyMock.createMock(DeviceConfigTest.class);
          mStubConfiguration.setTest(mockDeviceTest);
@@ -441,6 +452,7 @@
      *
      * @throws Exception if unexpected error occurs
      */
+    @Test
     public void testInvoke_testFail() throws Throwable {
         IllegalArgumentException exception = new IllegalArgumentException();
         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
@@ -465,6 +477,7 @@
      *
      * @throws Exception if unexpected error occurs
      */
+    @Test
     public void testInvoke_fatalError() throws Throwable {
         FatalHostError exception = new FatalHostError("error");
         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
@@ -489,6 +502,7 @@
      *
      * @throws Exception if unexpected error occurs
      */
+    @Test
     public void testInvoke_deviceNotAvail() throws Throwable {
         DeviceNotAvailableException exception = new DeviceNotAvailableException("ERROR", SERIAL);
         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
@@ -515,6 +529,7 @@
      *
      * @throws Exception if unexpected error occurs
      */
+    @Test
     public void testInvoke_buildError() throws Throwable {
         BuildError exception = new BuildError("error", mFakeDescriptor);
         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
@@ -538,6 +553,7 @@
      *
      * @throws Exception if unexpected error occurs
      */
+    @Test
     public void testInvoke_resume() throws Throwable {
         IResumableTest resumableTest = EasyMock.createMock(IResumableTest.class);
         mStubConfiguration.setTest(resumableTest);
@@ -700,6 +716,7 @@
      *
      * @throws Exception if unexpected error occurs
      */
+    @Test
     public void testInvoke_retry() throws Throwable {
         AssertionError exception = new AssertionError();
         IRetriableTest test = EasyMock.createMock(IRetriableTest.class);
@@ -720,9 +737,9 @@
 
     /**
      * Test the {@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
-     * ITestInvocationListener[])} scenario
-     * when a {@link ITargetCleaner} is part of the config.
+     * ITestInvocationListener[])} scenario when a {@link ITargetCleaner} is part of the config.
      */
+    @Test
     public void testInvoke_tearDown() throws Throwable {
          IRemoteTest test = EasyMock.createNiceMock(IRemoteTest.class);
          ITargetCleaner mockCleaner = EasyMock.createMock(ITargetCleaner.class);
@@ -741,10 +758,10 @@
 
     /**
      * Test the {@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
-     * ITestInvocationListener[])} scenario
-     * when a {@link ITargetCleaner} is part of the config, and the test throws a
-     * {@link DeviceNotAvailableException}.
+     * ITestInvocationListener[])} scenario when a {@link ITargetCleaner} is part of the config, and
+     * the test throws a {@link DeviceNotAvailableException}.
      */
+    @Test
     public void testInvoke_tearDown_deviceNotAvail() throws Throwable {
         DeviceNotAvailableException exception = new DeviceNotAvailableException("ERROR", SERIAL);
         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
@@ -776,10 +793,10 @@
 
     /**
      * Test the {@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
-     * ITestInvocationListener[])} scenario
-     * when a {@link ITargetCleaner} is part of the config, and the test throws a
-     * {@link RuntimeException}.
+     * ITestInvocationListener[])} scenario when a {@link ITargetCleaner} is part of the config, and
+     * the test throws a {@link RuntimeException}.
      */
+    @Test
     public void testInvoke_tearDown_runtime() throws Throwable {
         RuntimeException exception = new RuntimeException();
         IRemoteTest test = EasyMock.createMock(IRemoteTest.class);
@@ -808,10 +825,10 @@
 
     /**
      * Test the {@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
-     * ITestInvocationListener[])} scenario
-     * when there is {@link ITestInvocationListener} which implements the {@link ILogSaverListener}
-     * interface.
+     * ITestInvocationListener[])} scenario when there is {@link ITestInvocationListener} which
+     * implements the {@link ILogSaverListener} interface.
      */
+    @Test
     public void testInvoke_logFileSaved() throws Throwable {
         List<ITestInvocationListener> listenerList =
                 mStubConfiguration.getTestInvocationListeners();
@@ -878,9 +895,8 @@
         assertEquals(2, mUriCapture.getValue().size());
     }
 
-    /**
-     * Test the test-tag is set when the IBuildInfo's test-tag is not.
-     */
+    /** Test the test-tag is set when the IBuildInfo's test-tag is not. */
+    @Test
     public void testInvoke_testtag() throws Throwable {
         String[] commandLine = {"run", "empty"};
         mStubConfiguration.setCommandLine(commandLine);
@@ -914,6 +930,7 @@
      * Test the test-tag of the IBuildInfo is not modified when the CommandOption default test-tag
      * is not modified.
      */
+    @Test
     public void testInvoke_testtag_notset() throws Throwable {
         String[] commandLine = {"run", "empty"};
         mStubConfiguration.setCommandLine(commandLine);
@@ -939,9 +956,10 @@
     }
 
     /**
-     * Test the test-tag of the IBuildInfo is not set and Command Option is not set either.
-     * A default 'stub' test-tag is set to ensure reporting is done.
+     * Test the test-tag of the IBuildInfo is not set and Command Option is not set either. A
+     * default 'stub' test-tag is set to ensure reporting is done.
      */
+    @Test
     public void testInvoke_notesttag() throws Throwable {
         String[] commandLine = {"run", "empty"};
         mStubConfiguration.setCommandLine(commandLine);
@@ -975,9 +993,10 @@
     }
 
     /**
-     * Test the injection of test-tag from TestInvocation to the build provider via the
-     * {@link IInvocationContextReceiver}.
+     * Test the injection of test-tag from TestInvocation to the build provider via the {@link
+     * IInvocationContextReceiver}.
      */
+    @Test
     public void testInvoke_buildProviderNeedTestTag() throws Throwable {
         final String testTag = "THISISTHETAG";
         String[] commandLine = {"run", "empty"};
@@ -1202,6 +1221,7 @@
      * Test the {@link TestInvocation#invoke(IInvocationContext, IConfiguration, IRescheduler,
      * ITestInvocationListener[])} scenario with {@link IShardableTest}.
      */
+    @Test
     public void testInvoke_shardableTest_legacy() throws Throwable {
         String command = "empty --test-tag t";
         String[] commandLine = {"empty", "--test-tag", "t"};
@@ -1216,18 +1236,23 @@
         mStubConfiguration.setTest(test);
         mStubConfiguration.setCommandLine(commandLine);
         mMockBuildProvider.cleanUp(mMockBuildInfo);
+        // The keystore is cloned for each shard.
+        EasyMock.expect(mGlobalConfiguration.getKeyStoreFactory())
+                .andReturn(new StubKeyStoreFactory())
+                .times(2);
         setupInvoke();
         setupNShardInvocation(shardCount, command);
         mMockLogRegistry.dumpToGlobalLog(mMockLogger);
-        replayMocks(test, mockRescheduler, shard1, shard2);
+        replayMocks(test, mockRescheduler, shard1, shard2, mGlobalConfiguration);
         mTestInvocation.invoke(mStubInvocationMetadata, mStubConfiguration, mockRescheduler);
-        verifyMocks(test, mockRescheduler, shard1, shard2);
+        verifyMocks(test, mockRescheduler, shard1, shard2, mGlobalConfiguration);
     }
 
     /**
      * Test that {@link TestInvocation#logDeviceBatteryLevel(IInvocationContext, String)} is not
      * adding battery information for placeholder device.
      */
+    @Test
     public void testLogDeviceBatteryLevel_placeholderDevice() {
         final String fakeEvent = "event";
         IInvocationContext context = new InvocationContext();
@@ -1244,6 +1269,7 @@
      * Test that {@link TestInvocation#logDeviceBatteryLevel(IInvocationContext, String)} is adding
      * battery information for physical real device.
      */
+    @Test
     public void testLogDeviceBatteryLevel_physicalDevice() {
         final String fakeEvent = "event";
         IInvocationContext context = new InvocationContext();
@@ -1268,6 +1294,7 @@
      * Test that {@link TestInvocation#logDeviceBatteryLevel(IInvocationContext, String)} is adding
      * battery information for multiple physical real device.
      */
+    @Test
     public void testLogDeviceBatteryLevel_physicalDevice_multi() {
         final String fakeEvent = "event";
         IInvocationContext context = new InvocationContext();
@@ -1306,6 +1333,7 @@
      * Test that {@link TestInvocation#logDeviceBatteryLevel(IInvocationContext, String)} is adding
      * battery information for multiple physical real device, and ignore stub device if any.
      */
+    @Test
     public void testLogDeviceBatteryLevel_physicalDevice_stub_multi() {
         final String fakeEvent = "event";
         IInvocationContext context = new InvocationContext();
@@ -1426,6 +1454,7 @@
      * Test {@link INativeDevice#preInvocationSetup(IBuildInfo, List)} is called when command option
      * skip-pre-device-setup is not set.
      */
+    @Test
     public void testNotSkipPreDeviceSetup() throws Throwable {
         IInvocationContext context = new InvocationContext();
         ITestDevice device1 = EasyMock.createMock(ITestDevice.class);
@@ -1460,6 +1489,7 @@
      * Test {@link INativeDevice#preInvocationSetup(IBuildInfo info)} is not called when command
      * option skip-pre-device-setup is set.
      */
+    @Test
     public void testSkipPreDeviceSetup() throws Throwable {
         IInvocationContext context = new InvocationContext();
         ITestDevice device1 = EasyMock.createMock(ITestDevice.class);
@@ -1494,6 +1524,7 @@
      * Test when a {@link IDeviceBuildInfo} is passing through we do not attempt to add any external
      * directories when there is none coming from environment.
      */
+    @Test
     public void testInvoke_deviceInfoBuild_noEnv() throws Throwable {
         mTestInvocation =
                 new TestInvocation() {
@@ -1562,6 +1593,7 @@
      * Test when a {@link IDeviceBuildInfo} is passing through we attempt to add the external
      * directories to it when they are available.
      */
+    @Test
     public void testInvoke_deviceInfoBuild_withEnv() throws Throwable {
         File tmpTestsDir = FileUtil.createTempDir("invocation-tests-dir");
         File tmpExternalTestsDir = FileUtil.createTempDir("external-tf-dir");
@@ -1651,6 +1683,7 @@
      * Test when a {@link IDeviceBuildInfo} is passing through we do not attempt to add the external
      * directories to it, since {@link BuildInfoProperties} is set to skip the linking.
      */
+    @Test
     public void testInvoke_deviceInfoBuild_withEnv_andSkipProperty() throws Throwable {
         File tmpTestsDir = FileUtil.createTempDir("invocation-tests-dir");
         File tmpExternalTestsDir = FileUtil.createTempDir("external-tf-dir");
@@ -1745,6 +1778,7 @@
      * Test that when {@link IMetricCollector} are used, they wrap and call in sequence the listener
      * so all metrics end up on the final receiver.
      */
+    @Test
     public void testMetricCollectionChain() throws Throwable {
         IConfiguration configuration = new Configuration("test", "description");
         StubTest test = new StubTest();
@@ -1785,6 +1819,7 @@
      * Test that when a device collector is disabled, it will not be part of the initialization and
      * the collector chain.
      */
+    @Test
     public void testMetricCollectionChain_disabled() throws Throwable {
         IConfiguration configuration = new Configuration("test", "description");
         StubTest test = new StubTest();
@@ -1843,6 +1878,7 @@
     }
 
     /** Ensure post processors are called in order. */
+    @Test
     public void testProcessorCollectionChain() throws Throwable {
         mMockTestListener = EasyMock.createMock(ITestInvocationListener.class);
         List<ITestInvocationListener> listenerList = new ArrayList<ITestInvocationListener>(1);
diff --git a/tests/src/com/android/tradefed/util/net/HttpHelperTest.java b/tests/src/com/android/tradefed/util/net/HttpHelperTest.java
index bfb5a7b..53ae5b7 100644
--- a/tests/src/com/android/tradefed/util/net/HttpHelperTest.java
+++ b/tests/src/com/android/tradefed/util/net/HttpHelperTest.java
@@ -16,6 +16,9 @@
 
 package com.android.tradefed.util.net;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.Mockito.doNothing;
 
 import com.android.tradefed.util.IRunUtil;
@@ -24,8 +27,11 @@
 import com.android.tradefed.util.StreamUtil;
 import com.android.tradefed.util.net.IHttpHelper.DataSizeException;
 
-import junit.framework.TestCase;
-
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
 import org.mockito.Mockito;
 
 import java.io.ByteArrayInputStream;
@@ -36,36 +42,26 @@
 import java.net.HttpURLConnection;
 import java.net.URL;
 
-/**
- * Unit tests for {@link HttpHelper}.
- */
-public class HttpHelperTest extends TestCase {
+/** Unit tests for {@link HttpHelper}. */
+@RunWith(JUnit4.class)
+public class HttpHelperTest {
     private static final String TEST_URL_STRING = "http://foo";
     private static final String TEST_POST_DATA = "this is post data";
     private static final String TEST_DATA = "this is test data";
     private TestHttpHelper mHelper;
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
+    @Before
+    public void setUp() throws Exception {
         mHelper = new TestHttpHelper();
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
+    @After
+    public void tearDown() throws Exception {
         mHelper.close();
     }
 
-    /**
-     * Test {@link HttpHelper#buildParameters(MultiMap)}.
-     */
+    /** Test {@link HttpHelper#buildParameters(MultiMap)}. */
+    @Test
     public void testBuildParams() {
         MultiMap<String, String> paramMap = new MultiMap<String, String>();
         paramMap.put("key", "value");
@@ -89,9 +85,8 @@
         assertEquals("key%2Bf%3Fo%3Do%3B=value", mHelper.buildParameters(paramMap));
     }
 
-    /**
-     * Test {@link HttpHelper#buildUrl(String, MultiMap)} with simple parameters.
-     */
+    /** Test {@link HttpHelper#buildUrl(String, MultiMap)} with simple parameters. */
+    @Test
     public void testBuildUrl() {
         assertEquals("http://foo", mHelper.buildUrl(TEST_URL_STRING, null));
 
@@ -102,17 +97,17 @@
         assertEquals("http://foo?key=value", mHelper.buildUrl(TEST_URL_STRING, paramMap));
     }
 
-    /**
-     * Normal case test for {@link HttpHelper#doGet(String)}
-     */
+    /** Normal case test for {@link HttpHelper#doGet(String)} */
+    @Test
     public void testDoGet() throws IOException, DataSizeException {
         assertEquals(TEST_DATA, mHelper.doGet(TEST_URL_STRING));
     }
 
     /**
-     * Test that {@link HttpHelper#doGet(String)} throws {@link DataSizeException} when the
-     * remote stream returns too much data.
+     * Test that {@link HttpHelper#doGet(String)} throws {@link DataSizeException} when the remote
+     * stream returns too much data.
      */
+    @Test
     public void testDoGet_datasize() throws IOException {
         mHelper.close();
         mHelper = new TestHttpHelper() {
@@ -131,9 +126,8 @@
         }
     }
 
-    /**
-     * Normal case test for {@link HttpHelper#doGet(String, OutputStream)}
-     */
+    /** Normal case test for {@link HttpHelper#doGet(String, OutputStream)} */
+    @Test
     public void testDoGetStream() throws IOException {
         ByteArrayOutputStream out = new ByteArrayOutputStream();
 
@@ -143,9 +137,8 @@
         assertEquals(TEST_DATA, out.toString());
     }
 
-    /**
-     * Normal case test for {@link HttpHelper#doGetWithRetry(String)}.
-     */
+    /** Normal case test for {@link HttpHelper#doGetWithRetry(String)}. */
+    @Test
     public void testDoGetWithRetry() throws IOException, DataSizeException {
         assertEquals(TEST_DATA, mHelper.doGetWithRetry(TEST_URL_STRING));
     }
@@ -154,6 +147,7 @@
      * Test that {@link HttpHelper#doGetWithRetry(String)} throws a {@link DataSizeException} when
      * the remote stream returns too much data.
      */
+    @Test
     public void testDoGetWithRetry_datasize() throws IOException {
         mHelper.close();
         mHelper = new TestHttpHelper() {
@@ -173,9 +167,10 @@
     }
 
     /**
-     * Test that {@link HttpHelper#doGetWithRetry(String)} throws a {@link IOException} if an
-     * {@link IOException} is thrown on each attempt.
+     * Test that {@link HttpHelper#doGetWithRetry(String)} throws a {@link IOException} if an {@link
+     * IOException} is thrown on each attempt.
      */
+    @Test
     public void testDoGetWithRetry_ioexception() throws DataSizeException {
         mHelper.close();
         mHelper = new TestHttpHelper() {
@@ -197,6 +192,7 @@
      * Test that {@link HttpHelper#doGetWithRetry(String)} returns data if an {@link IOException} is
      * thrown on the first attempt, but is fine on the second attempt.
      */
+    @Test
     public void testDoGetWithRetry_retry() throws IOException, DataSizeException {
         mHelper.close();
         RunUtil mockRunUtil = Mockito.spy(RunUtil.class);
@@ -224,18 +220,18 @@
         assertEquals(TEST_DATA, mHelper.doGetWithRetry(TEST_URL_STRING));
     }
 
-    /**
-     * Normal case test for {@link HttpHelper#doPostWithRetry(String, String)}.
-     */
+    /** Normal case test for {@link HttpHelper#doPostWithRetry(String, String)}. */
+    @Test
     public void testDoPostWithRetry() throws IOException, DataSizeException {
         assertEquals(TEST_DATA, mHelper.doPostWithRetry(TEST_URL_STRING, TEST_POST_DATA));
         assertEquals(TEST_POST_DATA, mHelper.getOutputStream().toString());
     }
 
     /**
-     * Test that {@link HttpHelper#doPostWithRetry(String, String)} throws a
-     * {@link DataSizeException} when the remote stream returns too much data.
+     * Test that {@link HttpHelper#doPostWithRetry(String, String)} throws a {@link
+     * DataSizeException} when the remote stream returns too much data.
      */
+    @Test
     public void testDoPostWithRetry_datasize() throws IOException {
         mHelper.close();
         mHelper = new TestHttpHelper() {
@@ -258,6 +254,7 @@
      * Test that {@link HttpHelper#doPostWithRetry(String, String)} throws a {@link IOException} if
      * an {@link IOException} is thrown on each attempt.
      */
+    @Test
     public void testDoPostWithRetry_ioexception() throws DataSizeException {
         mHelper.close();
         mHelper = new TestHttpHelper() {
@@ -277,24 +274,26 @@
     }
 
     /**
-     * Test that {@link HttpHelper#doPostWithRetry(String, String)} returns data if an
-     * {@link IOException} is thrown on the first attempt, but is fine on the second attempt.
+     * Test that {@link HttpHelper#doPostWithRetry(String, String)} returns data if an {@link
+     * IOException} is thrown on the first attempt, but is fine on the second attempt.
      */
+    @Test
     public void testDoPostWithRetry_retry() throws IOException, DataSizeException {
         mHelper.close();
-        mHelper = new TestHttpHelper() {
-            boolean mExceptionThrown = false;
+        mHelper =
+                new TestHttpHelper() {
+                    boolean mExceptionThrown = false;
 
-            @Override
-            public HttpURLConnection createConnection(URL url, String method, String contentType)
-                    throws IOException {
-                if (!mExceptionThrown) {
-                    mExceptionThrown = true;
-                    throw new IOException();
-                }
-                return super.createConnection(url, method, contentType);
-            }
-        };
+                    @Override
+                    public HttpURLConnection createConnection(
+                            URL url, String method, String contentType) throws IOException {
+                        if (!mExceptionThrown) {
+                            mExceptionThrown = true;
+                            throw new IOException("first failure");
+                        }
+                        return super.createConnection(url, method, contentType);
+                    }
+                };
 
         assertEquals(TEST_DATA, mHelper.doPostWithRetry(TEST_URL_STRING, TEST_POST_DATA));
         assertEquals(TEST_POST_DATA, mHelper.getOutputStream().toString());