Merge "Move testNetworkFailedRollback (2/n)"
diff --git a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
index 2c2e828..0393248 100644
--- a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
+++ b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
@@ -16,22 +16,98 @@
 
 package com.android.tests.rollback.host;
 
+import static org.junit.Assert.assertTrue;
+import static org.testng.Assert.assertThrows;
+
+import com.android.tradefed.device.LogcatReceiver;
+import com.android.tradefed.result.InputStreamSource;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Runs the network rollback tests.
  */
 @RunWith(DeviceJUnit4ClassRunner.class)
 public class NetworkStagedRollbackTest extends BaseHostJUnit4Test {
     /**
+     * Runs the given phase of a test by calling into the device.
+     * Throws an exception if the test phase fails.
+     * <p>
+     * For example, <code>runPhase("testApkOnlyEnableRollback");</code>
+     */
+    private void runPhase(String phase) throws Exception {
+        assertTrue(runDeviceTests("com.android.tests.rollback",
+                "com.android.tests.rollback.NetworkStagedRollbackTest",
+                phase));
+    }
+
+    private static final String REASON_EXPLICIT_HEALTH_CHECK = "REASON_EXPLICIT_HEALTH_CHECK";
+
+    private static final String ROLLBACK_INITIATE = "ROLLBACK_INITIATE";
+    private static final String ROLLBACK_BOOT_TRIGGERED = "ROLLBACK_BOOT_TRIGGERED";
+
+    private LogcatReceiver mReceiver;
+
+    @Before
+    public void setUp() throws Exception {
+        mReceiver =  new LogcatReceiver(getDevice(), "logcat -s WatchdogRollbackLogger",
+                getDevice().getOptions().getMaxLogcatDataSize(), 0);
+        mReceiver.start();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mReceiver.stop();
+        mReceiver.clear();
+    }
+
+    /**
      * Tests failed network health check triggers watchdog staged rollbacks.
      */
     @Test
     public void testNetworkFailedRollback() throws Exception {
+        try {
+            // Disconnect internet so we can test network health triggered rollbacks
+            getDevice().executeShellCommand("svc wifi disable");
+            getDevice().executeShellCommand("svc data disable");
+
+            runPhase("testNetworkFailedRollback_Phase1");
+            // Reboot device to activate staged package
+            getDevice().reboot();
+
+            // Verify rollback was enabled
+            runPhase("testNetworkFailedRollback_Phase2");
+            assertThrows(AssertionError.class, () -> runPhase("testNetworkFailedRollback_Phase3"));
+
+            getDevice().waitForDeviceAvailable();
+            // Verify rollback was executed after health check deadline
+            runPhase("testNetworkFailedRollback_Phase4");
+            InputStreamSource logcatStream = mReceiver.getLogcatData();
+            try {
+                List<String> watchdogEvents = getWatchdogLoggingEvents(logcatStream);
+                assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
+                        REASON_EXPLICIT_HEALTH_CHECK, null));
+                assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
+                        null, null));
+            } finally {
+                logcatStream.close();
+            }
+        } finally {
+            // Reconnect internet again so we won't break tests which assume internet available
+            getDevice().executeShellCommand("svc wifi enable");
+            getDevice().executeShellCommand("svc data enable");
+        }
     }
 
     /**
@@ -40,4 +116,57 @@
     @Test
     public void testNetworkPassedDoesNotRollback() throws Exception {
     }
+
+    /**
+     * Returns a list of all Watchdog logging events which have occurred.
+     */
+    private List<String> getWatchdogLoggingEvents(InputStreamSource inputStreamSource)
+            throws Exception {
+        List<String> watchdogEvents = new ArrayList<>();
+        InputStream inputStream = inputStreamSource.createInputStream();
+        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
+        String line;
+        while ((line = reader.readLine()) != null) {
+            if (line.contains("Watchdog event occurred")) {
+                watchdogEvents.add(line);
+            }
+        }
+        return watchdogEvents;
+    }
+
+    /**
+     * Returns whether a Watchdog event has occurred that matches the given criteria.
+     *
+     * Check the value of all non-null parameters against the list of Watchdog events that have
+     * occurred, and return {@code true} if an event exists which matches all criteria.
+     */
+    private boolean watchdogEventOccurred(List<String> loggingEvents,
+            String type, String logPackage,
+            String rollbackReason, String failedPackageName) throws Exception {
+        List<String> eventCriteria = new ArrayList<>();
+        if (type != null) {
+            eventCriteria.add("type: " + type);
+        }
+        if (logPackage != null) {
+            eventCriteria.add("logPackage: " + logPackage);
+        }
+        if (rollbackReason != null) {
+            eventCriteria.add("rollbackReason: " + rollbackReason);
+        }
+        if (failedPackageName != null) {
+            eventCriteria.add("failedPackageName: " + failedPackageName);
+        }
+        for (String loggingEvent: loggingEvents) {
+            boolean matchesCriteria = true;
+            for (String criterion: eventCriteria) {
+                if (!loggingEvent.contains(criterion)) {
+                    matchesCriteria = false;
+                }
+            }
+            if (matchesCriteria) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
index 04004d6..e5c8a68 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
@@ -16,9 +16,143 @@
 
 package com.android.tests.rollback;
 
+import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat;
+import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage;
+
+import android.Manifest;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.rollback.RollbackManager;
+import android.os.ParcelFileDescriptor;
+import android.provider.DeviceConfig;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.cts.install.lib.Install;
+import com.android.cts.install.lib.InstallUtils;
+import com.android.cts.install.lib.TestApp;
+import com.android.cts.rollback.lib.RollbackUtils;
+
+import libcore.io.IoUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
 @RunWith(JUnit4.class)
 public class NetworkStagedRollbackTest {
+    private static final String NETWORK_STACK_CONNECTOR_CLASS =
+            "android.net.INetworkStackConnector";
+    private static final String PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS =
+            "watchdog_request_timeout_millis";
+
+    private static final TestApp NETWORK_STACK = new TestApp("NetworkStack",
+            getNetworkStackPackageName(), -1, false, findNetworkStackApk());
+
+    private static File findNetworkStackApk() {
+        final File apk = new File("/system/priv-app/NetworkStack/NetworkStack.apk");
+        if (apk.isFile()) {
+            return apk;
+        }
+        return new File("/system/priv-app/NetworkStackNext/NetworkStackNext.apk");
+    }
+
+    /**
+     * Adopts common shell permissions needed for rollback tests.
+     */
+    @Before
+    public void adoptShellPermissions() {
+        InstallUtils.adoptShellPermissionIdentity(
+                Manifest.permission.INSTALL_PACKAGES,
+                Manifest.permission.DELETE_PACKAGES,
+                Manifest.permission.TEST_MANAGE_ROLLBACKS,
+                Manifest.permission.FORCE_STOP_PACKAGES,
+                Manifest.permission.WRITE_DEVICE_CONFIG);
+    }
+
+    /**
+     * Drops shell permissions needed for rollback tests.
+     */
+    @After
+    public void dropShellPermissions() {
+        InstallUtils.dropShellPermissionIdentity();
+    }
+
+    @Test
+    public void testNetworkFailedRollback_Phase1() throws Exception {
+        // Remove available rollbacks and uninstall NetworkStack on /data/
+        RollbackManager rm = RollbackUtils.getRollbackManager();
+        String networkStack = getNetworkStackPackageName();
+
+        rm.expireRollbackForPackage(networkStack);
+        uninstallNetworkStackPackage();
+
+        assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+                networkStack)).isNull();
+
+        // Reduce health check deadline
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
+                PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS,
+                Integer.toString(120000), false);
+        // Simulate re-installation of new NetworkStack with rollbacks enabled
+        installNetworkStackPackage();
+    }
+
+    @Test
+    public void testNetworkFailedRollback_Phase2() throws Exception {
+        RollbackManager rm = RollbackUtils.getRollbackManager();
+        assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+                getNetworkStackPackageName())).isNotNull();
+
+        // Sleep for < health check deadline
+        Thread.sleep(TimeUnit.SECONDS.toMillis(5));
+        // Verify rollback was not executed before health check deadline
+        assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
+                getNetworkStackPackageName())).isNull();
+    }
+
+    @Test
+    public void testNetworkFailedRollback_Phase3() throws Exception {
+        // Sleep for > health check deadline (120s to trigger rollback + 120s to reboot)
+        // The device is expected to reboot during sleeping. This device method will fail and
+        // the host will catch the assertion. If reboot doesn't happen, the host will fail the
+        // assertion.
+        Thread.sleep(TimeUnit.SECONDS.toMillis(240));
+    }
+
+    @Test
+    public void testNetworkFailedRollback_Phase4() throws Exception {
+        RollbackManager rm = RollbackUtils.getRollbackManager();
+        assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
+                getNetworkStackPackageName())).isNotNull();
+    }
+
+    private static String getNetworkStackPackageName() {
+        Intent intent = new Intent(NETWORK_STACK_CONNECTOR_CLASS);
+        ComponentName comp = intent.resolveSystemService(
+                InstrumentationRegistry.getInstrumentation().getContext().getPackageManager(), 0);
+        return comp.getPackageName();
+    }
+
+    private static void installNetworkStackPackage() throws Exception {
+        Install.single(NETWORK_STACK).setStaged().setEnableRollback()
+                .addInstallFlags(PackageManager.INSTALL_REPLACE_EXISTING).commit();
+    }
+
+    private static void uninstallNetworkStackPackage() {
+        // Uninstall the package as a privileged user so we won't fail due to permission.
+        runShellCommand("pm uninstall " + getNetworkStackPackageName());
+    }
+
+    private static void runShellCommand(String cmd) {
+        ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .executeShellCommand(cmd);
+        IoUtils.closeQuietly(pfd);
+    }
 }
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 0fdcbc5..bddd93c 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -274,55 +274,6 @@
                 TestApp.B)).isNotNull();
     }
 
-    @Test
-    public void testNetworkFailedRollback_Phase1() throws Exception {
-        // Remove available rollbacks and uninstall NetworkStack on /data/
-        RollbackManager rm = RollbackUtils.getRollbackManager();
-        String networkStack = getNetworkStackPackageName();
-
-        rm.expireRollbackForPackage(networkStack);
-        uninstallNetworkStackPackage();
-
-        assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
-                        networkStack)).isNull();
-
-        // Reduce health check deadline
-        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
-                PROPERTY_WATCHDOG_REQUEST_TIMEOUT_MILLIS,
-                Integer.toString(120000), false);
-        // Simulate re-installation of new NetworkStack with rollbacks enabled
-        installNetworkStackPackage();
-    }
-
-    @Test
-    public void testNetworkFailedRollback_Phase2() throws Exception {
-        RollbackManager rm = RollbackUtils.getRollbackManager();
-        assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
-                        getNetworkStackPackageName())).isNotNull();
-
-        // Sleep for < health check deadline
-        Thread.sleep(TimeUnit.SECONDS.toMillis(5));
-        // Verify rollback was not executed before health check deadline
-        assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
-                        getNetworkStackPackageName())).isNull();
-    }
-
-    @Test
-    public void testNetworkFailedRollback_Phase3() throws Exception {
-        // Sleep for > health check deadline (120s to trigger rollback + 120s to reboot)
-        // The device is expected to reboot during sleeping. This device method will fail and
-        // the host will catch the assertion. If reboot doesn't happen, the host will fail the
-        // assertion.
-        Thread.sleep(TimeUnit.SECONDS.toMillis(240));
-    }
-
-    @Test
-    public void testNetworkFailedRollback_Phase4() throws Exception {
-        RollbackManager rm = RollbackUtils.getRollbackManager();
-        assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
-                        getNetworkStackPackageName())).isNotNull();
-    }
-
     private static String getNetworkStackPackageName() {
         Intent intent = new Intent(NETWORK_STACK_CONNECTOR_CLASS);
         ComponentName comp = intent.resolveSystemService(
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 032f182..3c5eaef 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -228,44 +228,6 @@
     }
 
     /**
-     * Tests failed network health check triggers watchdog staged rollbacks.
-     */
-    @Test
-    public void testNetworkFailedRollback() throws Exception {
-        try {
-            // Disconnect internet so we can test network health triggered rollbacks
-            getDevice().executeShellCommand("svc wifi disable");
-            getDevice().executeShellCommand("svc data disable");
-
-            runPhase("testNetworkFailedRollback_Phase1");
-            // Reboot device to activate staged package
-            getDevice().reboot();
-
-            // Verify rollback was enabled
-            runPhase("testNetworkFailedRollback_Phase2");
-            assertThrows(AssertionError.class, () -> runPhase("testNetworkFailedRollback_Phase3"));
-
-            getDevice().waitForDeviceAvailable();
-            // Verify rollback was executed after health check deadline
-            runPhase("testNetworkFailedRollback_Phase4");
-            InputStreamSource logcatStream = mReceiver.getLogcatData();
-            try {
-                List<String> watchdogEvents = getWatchdogLoggingEvents(logcatStream);
-                assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_INITIATE, null,
-                                REASON_EXPLICIT_HEALTH_CHECK, null));
-                assertTrue(watchdogEventOccurred(watchdogEvents, ROLLBACK_BOOT_TRIGGERED, null,
-                        null, null));
-            } finally {
-                logcatStream.close();
-            }
-        } finally {
-            // Reconnect internet again so we won't break tests which assume internet available
-            getDevice().executeShellCommand("svc wifi enable");
-            getDevice().executeShellCommand("svc data enable");
-        }
-    }
-
-    /**
      * Tests passed network health check does not trigger watchdog staged rollbacks.
      */
     @Test
diff --git a/tests/RollbackTest/TEST_MAPPING b/tests/RollbackTest/TEST_MAPPING
index fefde5b..0f4c460 100644
--- a/tests/RollbackTest/TEST_MAPPING
+++ b/tests/RollbackTest/TEST_MAPPING
@@ -7,6 +7,9 @@
       "name": "StagedRollbackTest"
     },
     {
+      "name": "NetworkStagedRollbackTest"
+    },
+    {
       "name": "MultiUserRollbackTest"
     }
   ]