RootTargetPreparer: add option to ignore failure and carry on with setup

In some scenarios tests (e.g CtsInitTestCases, CtsFsMgrTestCases) are
shared between different test suites (e.g. cts, vts) which means that
some of the tests cases require root, while others don't.

Adding an option to ignore failure of `adb root` will make it possible
to run those tests on both user and userdebug builds via the same
command (e.g. atest CtsInitTestCases).

Test: locally added RootTargetPreparer to CtsInitTestCases
Test: run atest CtsInitTestCases on aosp_blueline-user
Test: run_tradefed_tests.sh
Change-Id: I26d2b9785ebce29904ecbdd2358d2e354f78cab6
diff --git a/test_framework/com/android/tradefed/targetprep/RootTargetPreparer.java b/test_framework/com/android/tradefed/targetprep/RootTargetPreparer.java
index 50ddaae..8d6031b 100644
--- a/test_framework/com/android/tradefed/targetprep/RootTargetPreparer.java
+++ b/test_framework/com/android/tradefed/targetprep/RootTargetPreparer.java
@@ -15,12 +15,14 @@
  */
 package com.android.tradefed.targetprep;
 
+import com.android.tradefed.command.remote.DeviceDescriptor;
 import com.android.tradefed.config.Option;
 import com.android.tradefed.config.OptionClass;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.device.StubDevice;
 import com.android.tradefed.invoker.TestInformation;
+import com.android.tradefed.log.LogUtil.CLog;
 
 /**
  * Target preparer that performs "adb root" or "adb unroot" based on option "force-root".
@@ -39,6 +41,11 @@
                             + "root during setup.")
     private boolean mForceRoot = true;
 
+    @Option(
+            name = "throw-on-error",
+            description = "Throws TargetSetupError if adb root/unroot fails")
+    private boolean mThrowOnError = true;
+
     @Override
     public void setUp(TestInformation testInfo)
             throws TargetSetupError, BuildError, DeviceNotAvailableException {
@@ -49,9 +56,9 @@
         }
         mWasRoot = device.isAdbRoot();
         if (!mWasRoot && mForceRoot && !device.enableAdbRoot()) {
-            throw new TargetSetupError("Failed to adb root device", device.getDeviceDescriptor());
+            throwOrLog("Failed to adb root device", device.getDeviceDescriptor());
         } else if (mWasRoot && !mForceRoot && !device.disableAdbRoot()) {
-            throw new TargetSetupError("Failed to adb unroot device", device.getDeviceDescriptor());
+            throwOrLog("Failed to adb unroot device", device.getDeviceDescriptor());
         }
     }
 
@@ -68,4 +75,13 @@
             device.enableAdbRoot();
         }
     }
+
+    private void throwOrLog(String message, DeviceDescriptor deviceDescriptor)
+            throws TargetSetupError {
+        if (mThrowOnError) {
+            throw new TargetSetupError(message, deviceDescriptor);
+        } else {
+            CLog.w(message + " " + deviceDescriptor);
+        }
+    }
 }
diff --git a/tests/src/com/android/tradefed/targetprep/RootTargetPreparerTest.java b/tests/src/com/android/tradefed/targetprep/RootTargetPreparerTest.java
index e28d420..22c74cc 100644
--- a/tests/src/com/android/tradefed/targetprep/RootTargetPreparerTest.java
+++ b/tests/src/com/android/tradefed/targetprep/RootTargetPreparerTest.java
@@ -124,4 +124,36 @@
 
         mRootTargetPreparer.setUp(mTestInfo);
     }
+
+    @Test
+    public void testSetUpFail_forceRoot_ignoresFailure() throws Exception {
+        OptionSetter setter = new OptionSetter(mRootTargetPreparer);
+        setter.setOptionValue("throw-on-error", "false");
+
+        EasyMock.expect(mMockDevice.isAdbRoot()).andReturn(false).once();
+        EasyMock.expect(mMockDevice.enableAdbRoot()).andReturn(false).once();
+        EasyMock.expect(mMockDevice.getDeviceDescriptor()).andReturn(null).once();
+        EasyMock.expect(mMockDevice.disableAdbRoot()).andReturn(true).once();
+        EasyMock.replay(mMockDevice, mMockBuildInfo);
+
+        mRootTargetPreparer.setUp(mTestInfo);
+        mRootTargetPreparer.tearDown(mTestInfo, null);
+    }
+
+    @Test
+    public void testSetUpFail_forceUnroot_ignoresFailure() throws Exception {
+        OptionSetter setter = new OptionSetter(mRootTargetPreparer);
+        setter.setOptionValue("force-root", "false");
+        setter.setOptionValue("throw-on-error", "false");
+
+        EasyMock.expect(mMockDevice.isAdbRoot()).andReturn(true).once();
+        EasyMock.expect(mMockDevice.disableAdbRoot()).andReturn(false).once();
+        EasyMock.expect(mMockDevice.getDeviceDescriptor()).andReturn(null).once();
+        EasyMock.expect(mMockDevice.enableAdbRoot()).andReturn(true).once();
+        EasyMock.replay(mMockDevice, mMockBuildInfo);
+
+        mRootTargetPreparer.setUp(mTestInfo);
+        mRootTargetPreparer.tearDown(mTestInfo, null);
+        EasyMock.verify(mMockDevice, mMockBuildInfo);
+    }
 }