Atest: Add disable-teardown option.

Test: atest -dv CtsAnimationTestCases:EvaluatorTest
      atest -tv CtsAnimationTestCases:EvaluatorTest
      ./run_tradefed_tests.sh
      ./run_tradefed_presubmit.sh

Bug: b/73820366

Change-Id: I4d992eb5c1fbdb246edca4518bf8067030fae753
(cherry picked from commit e99c2cb69a6ec8069dd07043c3be06ca4a16c0fc)
diff --git a/atest/atest.py b/atest/atest.py
index a3b7700..48edc38 100755
--- a/atest/atest.py
+++ b/atest/atest.py
@@ -249,7 +249,13 @@
     parser.add_argument('-i', '--install', action='append_const', dest='steps',
                         const=INSTALL_STEP, help='Install an APK.')
     parser.add_argument('-t', '--test', action='append_const', dest='steps',
-                        const=TEST_STEP, help='Run the tests.')
+                        const=TEST_STEP,
+                        help='Run the tests. WARNING: Many test configs force cleanup '
+                        'of device after test run. In this case, -d must be used in previous '
+                        'test run to disable cleanup, for -t to work. Otherwise, '
+                        'device will need to be setup again with -i.')
+    parser.add_argument('-d', '--disable-teardown', action='store_true',
+                        help='Disables test teardown and cleanup.')
     parser.add_argument('-m', REBUILD_MODULE_INFO_FLAG, action='store_true',
                         help='Forces a rebuild of the module-info.json file. '
                              'This may be necessary following a repo sync or '
@@ -352,6 +358,8 @@
     steps = args.steps or ALL_STEPS
     if INSTALL_STEP not in steps:
         extra_args[constants.DISABLE_INSTALL] = None
+    if args.disable_teardown:
+        extra_args[constants.DISABLE_TEARDOWN] = args.disable_teardown
     if args.generate_baseline:
         extra_args[constants.PRE_PATCH_ITERATIONS] = args.generate_baseline
     if args.generate_new_metrics:
diff --git a/atest/constants_default.py b/atest/constants_default.py
index 408a5a2..ae2c8d8 100644
--- a/atest/constants_default.py
+++ b/atest/constants_default.py
@@ -26,6 +26,7 @@
 # Arg constants.
 WAIT_FOR_DEBUGGER = 'WAIT_FOR_DEBUGGER'
 DISABLE_INSTALL = 'DISABLE_INSTALL'
+DISABLE_TEARDOWN = 'DISABLE_TEARDOWN'
 PRE_PATCH_ITERATIONS = 'PRE_PATCH_ITERATIONS'
 POST_PATCH_ITERATIONS = 'POST_PATCH_ITERATIONS'
 PRE_PATCH_FOLDER = 'PRE_PATCH_FOLDER'
diff --git a/atest/test_runners/atest_tf_test_runner.py b/atest/test_runners/atest_tf_test_runner.py
index fd1dec2..bb4318f 100644
--- a/atest/test_runners/atest_tf_test_runner.py
+++ b/atest/test_runners/atest_tf_test_runner.py
@@ -129,6 +129,9 @@
             if constants.DISABLE_INSTALL == arg:
                 args_to_append.append('--disable-target-preparers')
                 continue
+            if constants.DISABLE_TEARDOWN == arg:
+                args_to_append.append('--disable-teardown')
+                continue
             if constants.CUSTOM_ARGS == arg:
                 # We might need to sanitize it prior to appending but for now
                 # let's just treat it like a simple arg to pass on through.
diff --git a/src/com/android/tradefed/invoker/InvocationExecution.java b/src/com/android/tradefed/invoker/InvocationExecution.java
index a31bbda..360bf82 100644
--- a/src/com/android/tradefed/invoker/InvocationExecution.java
+++ b/src/com/android/tradefed/invoker/InvocationExecution.java
@@ -233,6 +233,10 @@
                 multiPreparers.listIterator(multiPreparers.size());
         while (iterator.hasPrevious()) {
             IMultiTargetPreparer multipreparer = iterator.previous();
+            if (multipreparer.isDisabled() || multipreparer.isTearDownDisabled()) {
+                CLog.d("%s has been disabled. skipping.", multipreparer);
+                continue;
+            }
             CLog.d("Starting multi target tearDown '%s'", multipreparer);
             multipreparer.tearDown(context, throwable);
             CLog.d("Done with multi target tearDown '%s'", multipreparer);
@@ -250,7 +254,7 @@
                 if (preparer instanceof ITargetCleaner) {
                     ITargetCleaner cleaner = (ITargetCleaner) preparer;
                     // do not call the cleaner if it was disabled
-                    if (cleaner.isDisabled()) {
+                    if (cleaner.isDisabled() || cleaner.isTearDownDisabled()) {
                         CLog.d("%s has been disabled. skipping.", cleaner);
                         continue;
                     }
@@ -294,7 +298,7 @@
                 ITargetPreparer preparer = itr.previous();
                 if (preparer instanceof IHostCleaner) {
                     IHostCleaner cleaner = (IHostCleaner) preparer;
-                    if (preparer.isDisabled()) {
+                    if (preparer.isDisabled() || preparer.isTearDownDisabled()) {
                         CLog.d("%s has been disabled. skipping.", cleaner);
                         continue;
                     }
diff --git a/src/com/android/tradefed/targetprep/BaseTargetPreparer.java b/src/com/android/tradefed/targetprep/BaseTargetPreparer.java
index 8835e33..b0d0ee4 100644
--- a/src/com/android/tradefed/targetprep/BaseTargetPreparer.java
+++ b/src/com/android/tradefed/targetprep/BaseTargetPreparer.java
@@ -26,6 +26,12 @@
     @Option(name = "disable", description = "disables the target preparer")
     private boolean mDisable = false;
 
+    @Option(
+        name = "disable-tear-down",
+        description = "disables the clean up step of a target cleaner"
+    )
+    private boolean mDisableTearDown = false;
+
     /** {@inheritDoc} */
     @Override
     public final boolean isDisabled() {
@@ -34,7 +40,19 @@
 
     /** {@inheritDoc} */
     @Override
+    public final boolean isTearDownDisabled() {
+        return mDisableTearDown;
+    }
+
+    /** {@inheritDoc} */
+    @Override
     public final void setDisable(boolean isDisabled) {
         mDisable = isDisabled;
     }
+
+    /** {@inheritDoc} */
+    @Override
+    public final void setDisableTearDown(boolean isDisabled) {
+        mDisableTearDown = isDisabled;
+    }
 }
diff --git a/src/com/android/tradefed/targetprep/multi/BaseMultiTargetPreparer.java b/src/com/android/tradefed/targetprep/multi/BaseMultiTargetPreparer.java
index 5d9cc92..c6f00f7 100644
--- a/src/com/android/tradefed/targetprep/multi/BaseMultiTargetPreparer.java
+++ b/src/com/android/tradefed/targetprep/multi/BaseMultiTargetPreparer.java
@@ -23,6 +23,12 @@
     @Option(name = "disable", description = "disables the target preparer")
     private boolean mDisable = false;
 
+    @Option(
+        name = "disable-tear-down",
+        description = "disables the clean up step of a target cleaner"
+    )
+    private boolean mDisableTearDown = false;
+
     /** {@inheritDoc} */
     @Override
     public final boolean isDisabled() {
@@ -31,7 +37,20 @@
 
     /** {@inheritDoc} */
     @Override
+    public final boolean isTearDownDisabled() {
+        return mDisableTearDown;
+    }
+
+    /** {@inheritDoc} */
+    @Override
     public final void setDisable(boolean isDisabled) {
         mDisable = isDisabled;
     }
+
+    /** {@inheritDoc} */
+    @Override
+    public final void setDisableTearDown(boolean isDisabled) {
+        mDisableTearDown = isDisabled;
+    }
+
 }
diff --git a/src/com/android/tradefed/testtype/suite/AtestRunner.java b/src/com/android/tradefed/testtype/suite/AtestRunner.java
index d750252..448c030 100644
--- a/src/com/android/tradefed/testtype/suite/AtestRunner.java
+++ b/src/com/android/tradefed/testtype/suite/AtestRunner.java
@@ -69,9 +69,14 @@
 
     @Option(
         name = "disable-target-preparers",
-        description = "Skip the target preparer steps enumerated in test config."
+        description =
+                "Skip the target preparer steps enumerated in test config. Skips the teardown step "
+                        + "as well."
     )
-    private boolean mSkipInstall = false;
+    private boolean mSkipSetUp = false;
+
+    @Option(name = "disable-teardown", description = "Skip the teardown of the target preparers.")
+    private boolean mSkipTearDown = false;
 
     @Option(
         name = "abi-name",
@@ -112,8 +117,8 @@
                 for (String filter : testInfo.filters) {
                     addFilter(testConfig, filter);
                 }
-                if (mSkipInstall) {
-                    disableTargetPreparers(testConfig);
+                if (mSkipSetUp || mSkipTearDown) {
+                    disableTargetPreparers(testConfig, mSkipSetUp, mSkipTearDown);
                 }
                 if (mDebug) {
                     addDebugger(testConfig);
@@ -241,12 +246,20 @@
     }
 
     /** Helper to disable TargetPreparers of a test. */
-    private void disableTargetPreparers(IConfiguration testConfig) {
+    private void disableTargetPreparers(
+            IConfiguration testConfig, boolean skipSetUp, boolean skipTearDown) {
         for (ITargetPreparer targetPreparer : testConfig.getTargetPreparers()) {
-            CLog.d(
-                    "%s: Disabling Target Preparer (%s)",
-                    testConfig.getName(), targetPreparer.getClass().getSimpleName());
-            targetPreparer.setDisable(true);
+            if (skipSetUp) {
+                CLog.d(
+                        "%s: Disabling Target Preparer (%s)",
+                        testConfig.getName(), targetPreparer.getClass().getSimpleName());
+                targetPreparer.setDisable(true);
+            } else if (skipTearDown) {
+                CLog.d(
+                        "%s: Disabling Target Preparer TearDown (%s)",
+                        testConfig.getName(), targetPreparer.getClass().getSimpleName());
+                targetPreparer.setDisableTearDown(true);
+            }
         }
     }
 }
diff --git a/src/com/android/tradefed/testtype/suite/ModuleDefinition.java b/src/com/android/tradefed/testtype/suite/ModuleDefinition.java
index 530c864..a016ab5 100644
--- a/src/com/android/tradefed/testtype/suite/ModuleDefinition.java
+++ b/src/com/android/tradefed/testtype/suite/ModuleDefinition.java
@@ -568,7 +568,7 @@
         List<IMultiTargetPreparer> cleanerList = new ArrayList<>(mMultiPreparers);
         Collections.reverse(cleanerList);
         for (IMultiTargetPreparer multiCleaner : cleanerList) {
-            if (multiCleaner.isDisabled()) {
+            if (multiCleaner.isDisabled() || multiCleaner.isTearDownDisabled()) {
                 // If disabled skip completely.
                 continue;
             }
@@ -585,7 +585,7 @@
                 if (preparer instanceof ITargetCleaner) {
                     ITargetCleaner cleaner = (ITargetCleaner) preparer;
                     // do not call the cleaner if it was disabled
-                    if (cleaner.isDisabled()) {
+                    if (cleaner.isDisabled() || cleaner.isTearDownDisabled()) {
                         CLog.d("%s has been disabled. skipping.", cleaner);
                         continue;
                     }
diff --git a/src/com/android/tradefed/util/IDisableable.java b/src/com/android/tradefed/util/IDisableable.java
index 3481917..a16515a 100644
--- a/src/com/android/tradefed/util/IDisableable.java
+++ b/src/com/android/tradefed/util/IDisableable.java
@@ -21,18 +21,33 @@
  */
 public interface IDisableable {
 
-    /** Returns True if the object should be disabled and skipped. False otherwise. */
+    /** Returns True if entire object disabled (skip both setup and teardown). False otherwise. */
     public default boolean isDisabled() {
         return false;
     }
 
+    /** Returns True if just teardown should be skipped. False otherwise. */
+    public default boolean isTearDownDisabled() {
+        return false;
+    }
+
     /**
-     * Sets whether or not the object should be disabled or not. Can be use to make an object
-     * disabled by default in the default constructor.
+     * Sets whether the object should be disabled. Disabled means that both setup and teardown steps
+     * should be skipped. Can be use to make an object disabled by default in the default
+     * constructor.
      *
      * @param isDisabled the state the object should be put in.
      */
     public default void setDisable(boolean isDisabled) {
         // TODO: Remove the default empty implementation
     }
+
+    /**
+     * Sets whether the teardown step in the object should be skipped. Setup step is still done.
+     *
+     * @param isDisabled the state the object should be put in.
+     */
+    public default void setDisableTearDown(boolean isDisabled) {
+        // Empty implementation to avoid having to implement everywhere.
+    }
 }
diff --git a/tests/src/com/android/tradefed/invoker/InvocationExecutionTest.java b/tests/src/com/android/tradefed/invoker/InvocationExecutionTest.java
index 04459d3..778f44f 100644
--- a/tests/src/com/android/tradefed/invoker/InvocationExecutionTest.java
+++ b/tests/src/com/android/tradefed/invoker/InvocationExecutionTest.java
@@ -77,6 +77,7 @@
         mConfig.setDeviceConfig(holder);
         mContext.addAllocatedDevice("default", EasyMock.createMock(ITestDevice.class));
         EasyMock.expect(cleaner.isDisabled()).andReturn(false);
+        EasyMock.expect(cleaner.isTearDownDisabled()).andReturn(false);
         cleaner.cleanUp(null, null);
         EasyMock.replay(cleaner);
         mExec.doCleanUp(mContext, mConfig, null);
@@ -95,6 +96,26 @@
         mConfig.setDeviceConfig(holder);
         mContext.addAllocatedDevice("default", EasyMock.createMock(ITestDevice.class));
         EasyMock.expect(cleaner.isDisabled()).andReturn(true);
+        // cleaner.isTearDownDisabled not expected, because isDisabled true stops || execution.
+        // cleanUp call is not expected
+        EasyMock.replay(cleaner);
+        mExec.doCleanUp(mContext, mConfig, null);
+        EasyMock.verify(cleaner);
+    }
+
+    /**
+     * Test that {@link InvocationExecution#doCleanUp(IInvocationContext, IConfiguration,
+     * Throwable)} properly use {@link IDisableable} isTearDownDisabled to prevent cleanup step.
+     */
+    @Test
+    public void testCleanUp_tearDownDisabled() throws Exception {
+        DeviceConfigurationHolder holder = new DeviceConfigurationHolder("default");
+        ITargetHostCleaner cleaner = EasyMock.createMock(ITargetHostCleaner.class);
+        holder.addSpecificConfig(cleaner);
+        mConfig.setDeviceConfig(holder);
+        mContext.addAllocatedDevice("default", EasyMock.createMock(ITestDevice.class));
+        EasyMock.expect(cleaner.isDisabled()).andReturn(false);
+        EasyMock.expect(cleaner.isTearDownDisabled()).andReturn(true);
         // cleanUp call is not expected
         EasyMock.replay(cleaner);
         mExec.doCleanUp(mContext, mConfig, null);
diff --git a/tests/src/com/android/tradefed/invoker/TestInvocationTest.java b/tests/src/com/android/tradefed/invoker/TestInvocationTest.java
index e244a75..e7eaa25 100644
--- a/tests/src/com/android/tradefed/invoker/TestInvocationTest.java
+++ b/tests/src/com/android/tradefed/invoker/TestInvocationTest.java
@@ -167,6 +167,7 @@
         mStubConfiguration.setBuildProvider(mMockBuildProvider);
 
         EasyMock.expect(mMockPreparer.isDisabled()).andStubReturn(false);
+        EasyMock.expect(mMockPreparer.isTearDownDisabled()).andStubReturn(false);
 
         List<IDeviceConfiguration> deviceConfigs = new ArrayList<IDeviceConfiguration>();
         IDeviceConfiguration device1 =
@@ -683,6 +684,7 @@
          IRemoteTest test = EasyMock.createNiceMock(IRemoteTest.class);
          ITargetCleaner mockCleaner = EasyMock.createMock(ITargetCleaner.class);
         EasyMock.expect(mockCleaner.isDisabled()).andReturn(false).times(2);
+        EasyMock.expect(mockCleaner.isTearDownDisabled()).andReturn(false);
          mockCleaner.setUp(mMockDevice, mMockBuildInfo);
          mockCleaner.tearDown(mMockDevice, mMockBuildInfo, null);
          mStubConfiguration.getTargetPreparers().add(mockCleaner);
@@ -707,6 +709,7 @@
         EasyMock.expectLastCall().andThrow(exception);
         ITargetCleaner mockCleaner = EasyMock.createMock(ITargetCleaner.class);
         EasyMock.expect(mockCleaner.isDisabled()).andReturn(false).times(2);
+        EasyMock.expect(mockCleaner.isTearDownDisabled()).andReturn(false);
         mockCleaner.setUp(mMockDevice, mMockBuildInfo);
         EasyMock.expectLastCall();
         mockCleaner.tearDown(mMockDevice, mMockBuildInfo, exception);
@@ -741,6 +744,7 @@
         EasyMock.expectLastCall().andThrow(exception);
         ITargetCleaner mockCleaner = EasyMock.createMock(ITargetCleaner.class);
         EasyMock.expect(mockCleaner.isDisabled()).andReturn(false).times(2);
+        EasyMock.expect(mockCleaner.isTearDownDisabled()).andReturn(false);
         mockCleaner.setUp(mMockDevice, mMockBuildInfo);
         // tearDown should be called
         mockCleaner.tearDown(mMockDevice, mMockBuildInfo, exception);
@@ -1522,6 +1526,7 @@
         mStubConfiguration.setCommandOptions(commandOption);
 
         EasyMock.expect(mMockPreparer.isDisabled()).andReturn(true);
+        // Not expect isTearDownDisabled.
 
         ITestInvocationListener listener = EasyMock.createStrictMock(ITestInvocationListener.class);
         listener.testLog(
@@ -1556,6 +1561,7 @@
         mStubConfiguration.setCommandOptions(commandOption);
 
         EasyMock.expect(mMockPreparer.isDisabled()).andReturn(true);
+        // Not expect isTearDownDisabled
 
         ITestInvocationListener listener = EasyMock.createStrictMock(ITestInvocationListener.class);
         listener.testLog(
@@ -1606,6 +1612,7 @@
         IRemoteTest test = EasyMock.createNiceMock(IRemoteTest.class);
         ITargetCleaner mockCleaner = EasyMock.createMock(ITargetCleaner.class);
         EasyMock.expect(mockCleaner.isDisabled()).andReturn(false).times(2);
+        EasyMock.expect(mockCleaner.isTearDownDisabled()).andReturn(false);
         mockCleaner.setUp(mMockDevice, mMockBuildInfo);
         mockCleaner.tearDown(mMockDevice, mMockBuildInfo, null);
         mStubConfiguration.getTargetPreparers().add(mockCleaner);
@@ -1667,6 +1674,7 @@
             IRemoteTest test = EasyMock.createNiceMock(IRemoteTest.class);
             ITargetCleaner mockCleaner = EasyMock.createMock(ITargetCleaner.class);
             EasyMock.expect(mockCleaner.isDisabled()).andReturn(false).times(2);
+            EasyMock.expect(mockCleaner.isTearDownDisabled()).andReturn(false);
             mockCleaner.setUp(mMockDevice, mMockBuildInfo);
             mockCleaner.tearDown(mMockDevice, mMockBuildInfo, null);
             mStubConfiguration.getTargetPreparers().add(mockCleaner);
@@ -1742,6 +1750,7 @@
             IRemoteTest test = EasyMock.createNiceMock(IRemoteTest.class);
             ITargetCleaner mockCleaner = EasyMock.createMock(ITargetCleaner.class);
             EasyMock.expect(mockCleaner.isDisabled()).andReturn(false).times(2);
+            EasyMock.expect(mockCleaner.isTearDownDisabled()).andReturn(false);
             mockCleaner.setUp(mMockDevice, mMockBuildInfo);
             mockCleaner.tearDown(mMockDevice, mMockBuildInfo, null);
             mStubConfiguration.getTargetPreparers().add(mockCleaner);
diff --git a/tests/src/com/android/tradefed/testtype/suite/AtestRunnerTest.java b/tests/src/com/android/tradefed/testtype/suite/AtestRunnerTest.java
index ad68b49..50cc5df 100644
--- a/tests/src/com/android/tradefed/testtype/suite/AtestRunnerTest.java
+++ b/tests/src/com/android/tradefed/testtype/suite/AtestRunnerTest.java
@@ -314,4 +314,31 @@
             assertTrue(!targetPreparer.isDisabled());
         }
     }
+
+    @Test
+    public void testDisableTearDown() throws Exception {
+        String filePath = truncateAndWrite(mTmpFile, mInfos.get("module1"));
+        OptionSetter setter = new OptionSetter(mSpyRunner);
+        setter.setOptionValue("disable-teardown", "true");
+        setter.setOptionValue("test-info-file", filePath);
+        LinkedHashMap<String, IConfiguration> configMap = mSpyRunner.loadTests();
+        assertEquals(1, configMap.size());
+        IConfiguration config = configMap.get("module1");
+        for (ITargetPreparer targetPreparer : config.getTargetPreparers()) {
+            assertTrue(targetPreparer.isTearDownDisabled());
+        }
+    }
+
+    @Test
+    public void testDisableTearDownUnset() throws Exception {
+        String filePath = truncateAndWrite(mTmpFile, mInfos.get("module1"));
+        OptionSetter setter = new OptionSetter(mSpyRunner);
+        setter.setOptionValue("test-info-file", filePath);
+        LinkedHashMap<String, IConfiguration> configMap = mSpyRunner.loadTests();
+        assertEquals(1, configMap.size());
+        IConfiguration config = configMap.get("module1");
+        for (ITargetPreparer targetPreparer : config.getTargetPreparers()) {
+            assertTrue(!targetPreparer.isTearDownDisabled());
+        }
+    }
 }
diff --git a/tests/src/com/android/tradefed/testtype/suite/ModuleDefinitionTest.java b/tests/src/com/android/tradefed/testtype/suite/ModuleDefinitionTest.java
index d9f52bf..2fa454d 100644
--- a/tests/src/com/android/tradefed/testtype/suite/ModuleDefinitionTest.java
+++ b/tests/src/com/android/tradefed/testtype/suite/ModuleDefinitionTest.java
@@ -214,6 +214,7 @@
         mMockTest.setBuild(EasyMock.eq(mMockBuildInfo));
         mMockTest.setDevice(EasyMock.eq(mMockDevice));
         mMockTest.run((ITestInvocationListener)EasyMock.anyObject());
+        EasyMock.expect(mMockCleaner.isTearDownDisabled()).andStubReturn(false);
         mMockCleaner.tearDown(EasyMock.eq(mMockDevice), EasyMock.eq(mMockBuildInfo),
                 EasyMock.isNull());
         mMockListener.testRunStarted(MODULE_NAME, 0);
@@ -245,6 +246,31 @@
     }
 
     /**
+     * Test that {@link ModuleDefinition#run(ITestInvocationListener)} is properly going through the
+     * execution flow and skip target cleanup if teardown is disabled.
+     */
+    @Test
+    public void testRun_disabledTearDown() throws Exception {
+        mModule.setBuild(mMockBuildInfo);
+        mModule.setDevice(mMockDevice);
+        // Setup expected from preparers.
+        EasyMock.expect(mMockPrep.isDisabled()).andReturn(false);
+        mMockPrep.setUp(EasyMock.eq(mMockDevice), EasyMock.eq(mMockBuildInfo));
+        EasyMock.expect(mMockCleaner.isDisabled()).andStubReturn(false);
+        mMockCleaner.setUp(EasyMock.eq(mMockDevice), EasyMock.eq(mMockBuildInfo));
+        mMockTest.setBuild(EasyMock.eq(mMockBuildInfo));
+        mMockTest.setDevice(EasyMock.eq(mMockDevice));
+        mMockTest.run((ITestInvocationListener) EasyMock.anyObject());
+        EasyMock.expect(mMockCleaner.isTearDownDisabled()).andStubReturn(true);
+        // But no teardown expected from Cleaner.
+        mMockListener.testRunStarted(MODULE_NAME, 0);
+        mMockListener.testRunEnded(EasyMock.anyLong(), (Map<String, String>) EasyMock.anyObject());
+        replayMocks();
+        mModule.run(mMockListener);
+        verifyMocks();
+    }
+
+    /**
      * Test that {@link ModuleDefinition#run(ITestInvocationListener)}
      */
     @Test
@@ -306,9 +332,11 @@
         mModule.setBuild(mMockBuildInfo);
         mModule.setDevice(mMockDevice);
         EasyMock.expect(mMockPrep.isDisabled()).andReturn(false);
+        // no isTearDownDisabled() expected for setup
         mMockPrep.setUp(EasyMock.eq(mMockDevice), EasyMock.eq(mMockBuildInfo));
         EasyMock.expect(mMockCleaner.isDisabled()).andStubReturn(false);
         mMockCleaner.setUp(EasyMock.eq(mMockDevice), EasyMock.eq(mMockBuildInfo));
+        EasyMock.expect(mMockCleaner.isTearDownDisabled()).andStubReturn(false);
         mMockCleaner.tearDown(
                 EasyMock.eq(mMockDevice), EasyMock.eq(mMockBuildInfo), EasyMock.isNull());
         mMockListener.testRunStarted(MODULE_NAME, testCount);
@@ -347,9 +375,11 @@
         mModule.setBuild(mMockBuildInfo);
         mModule.setDevice(mMockDevice);
         EasyMock.expect(mMockPrep.isDisabled()).andReturn(false);
+        // no isTearDownDisabled() expected for setup
         mMockPrep.setUp(EasyMock.eq(mMockDevice), EasyMock.eq(mMockBuildInfo));
         EasyMock.expect(mMockCleaner.isDisabled()).andStubReturn(false);
         mMockCleaner.setUp(EasyMock.eq(mMockDevice), EasyMock.eq(mMockBuildInfo));
+        EasyMock.expect(mMockCleaner.isTearDownDisabled()).andStubReturn(false);
         mMockCleaner.tearDown(
                 EasyMock.eq(mMockDevice), EasyMock.eq(mMockBuildInfo), EasyMock.isNull());
         EasyMock.expectLastCall().andThrow(new DeviceNotAvailableException());
@@ -553,9 +583,11 @@
         mModule.setBuild(mMockBuildInfo);
         mModule.setDevice(mMockDevice);
         EasyMock.expect(mMockPrep.isDisabled()).andReturn(false);
+        // no isTearDownDisabled() expected for setup
         mMockPrep.setUp(EasyMock.eq(mMockDevice), EasyMock.eq(mMockBuildInfo));
         EasyMock.expect(mMockCleaner.isDisabled()).andStubReturn(false);
         mMockCleaner.setUp(EasyMock.eq(mMockDevice), EasyMock.eq(mMockBuildInfo));
+        EasyMock.expect(mMockCleaner.isTearDownDisabled()).andStubReturn(false);
         mMockCleaner.tearDown(
                 EasyMock.eq(mMockDevice), EasyMock.eq(mMockBuildInfo), EasyMock.isNull());
         mMockLogSaverListener.testRunStarted(MODULE_NAME, 0);