summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGopinath Elanchezhian <gelanchezhian@google.com>2020-03-17 15:10:04 -0700
committerGopinath Elanchezhian <gelanchezhian@google.com>2020-03-17 23:00:16 +0000
commit89c496491e02ae9b78cd988c5ef41ca23a213884 (patch)
tree9854b3845c8941ccd4a5778bc76b832a2e1204dc
parent0c2761259069054c6c026b3b16bcdacdbe8505b9 (diff)
downloadandroid_platform_testing-89c496491e02ae9b78cd988c5ef41ca23a213884.tar.gz
android_platform_testing-89c496491e02ae9b78cd988c5ef41ca23a213884.tar.bz2
android_platform_testing-89c496491e02ae9b78cd988c5ef41ca23a213884.zip
DO NOT MERGE: Backport rss metric collector changes.
Bug: b/151336935 Test: RssSnapshotHelperTest, RssSnapshotListenerTest Change-Id: If1aa6282abefb9c697aff97f294134ba29a63bf0 Exclude merging into *-plus-aosp branches, since they already include the change. Merged-In: Ic9101a35c137b9e480c6183b0ef249e9b2b17a6f Merged-In: Ic571023b68fd4c398a57d10b9b4e80c7676eabd1 Merged-In: I75c3d7ce90d5edb995b79a3faa85f4244bc2f5e7
-rw-r--r--libraries/collectors-helper/memory/src/com/android/helpers/RssSnapshotHelper.java323
-rw-r--r--libraries/collectors-helper/memory/test/src/com/android/helpers/tests/RssSnapshotHelperTest.java156
-rw-r--r--libraries/device-collectors/src/main/java/android/device/collectors/RssSnapshotListener.java99
-rw-r--r--libraries/device-collectors/src/test/java/android/device/collectors/RssSnapshotListenerTest.java91
4 files changed, 669 insertions, 0 deletions
diff --git a/libraries/collectors-helper/memory/src/com/android/helpers/RssSnapshotHelper.java b/libraries/collectors-helper/memory/src/com/android/helpers/RssSnapshotHelper.java
new file mode 100644
index 00000000..fc947a75
--- /dev/null
+++ b/libraries/collectors-helper/memory/src/com/android/helpers/RssSnapshotHelper.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2019 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.helpers;
+
+import static com.android.helpers.MetricUtility.constructKey;
+
+import android.support.test.uiautomator.UiDevice;
+import android.util.Log;
+import androidx.test.InstrumentationRegistry;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.InputMismatchException;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * Helper to collect rss snapshot for a list of processes.
+ */
+public class RssSnapshotHelper implements ICollectorHelper<String> {
+ private static final String TAG = RssSnapshotHelper.class.getSimpleName();
+
+ private static final String DROP_CACHES_CMD = "echo %d > /proc/sys/vm/drop_caches";
+ private static final String PIDOF_CMD = "pidof %s";
+ public static final String ALL_PROCESSES_CMD = "ps -A";
+ private static final String SHOWMAP_CMD = "showmap -v %d";
+
+ public static final String RSS_METRIC_PREFIX = "showmap_rss_bytes";
+ public static final String OUTPUT_FILE_PATH_KEY = "showmap_output_file";
+ public static final String RSS_PROCESS_COUNT = "rss_process_count";
+
+ private String[] mProcessNames = null;
+ private String mTestOutputDir = null;
+ private String mTestOutputFile = null;
+
+ private int mDropCacheOption;
+ private boolean mCollectForAllProcesses = false;
+ private UiDevice mUiDevice;
+
+ // Map to maintain per-process rss.
+ private Map<String, String> mRssMap = new HashMap<>();
+
+ public void setUp(String testOutputDir, String... processNames) {
+ mProcessNames = processNames;
+ mTestOutputDir = testOutputDir;
+ mDropCacheOption = 0;
+ mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+ }
+
+ @Override
+ public boolean startCollecting() {
+ if (mTestOutputDir == null) {
+ Log.e(TAG, String.format("Invalid test setup"));
+ return false;
+ }
+
+ File directory = new File(mTestOutputDir);
+ String filePath =
+ String.format("%s/rss_snapshot%d.txt", mTestOutputDir, UUID.randomUUID().hashCode());
+ File file = new File(filePath);
+
+ // Make sure directory exists and file does not
+ if (directory.exists()) {
+ if (file.exists() && !file.delete()) {
+ Log.e(TAG, String.format("Failed to delete result output file %s", filePath));
+ return false;
+ }
+ } else {
+ if (!directory.mkdirs()) {
+ Log.e(TAG, String.format("Failed to create result output directory %s", mTestOutputDir));
+ return false;
+ }
+ }
+
+ // Create an empty file to fail early in case there are no write permissions
+ try {
+ if (!file.createNewFile()) {
+ // This should not happen unless someone created the file right after we deleted it
+ Log.e(TAG, String.format("Race with another user of result output file %s", filePath));
+ return false;
+ }
+ } catch (IOException e) {
+ Log.e(TAG, String.format("Failed to create result output file %s", filePath), e);
+ return false;
+ }
+
+ mTestOutputFile = filePath;
+ return true;
+ }
+
+ @Override
+ public Map<String, String> getMetrics() {
+ try {
+ // Drop cache if requested
+ if (mDropCacheOption > 0) {
+ dropCache(mDropCacheOption);
+ }
+
+ if (mCollectForAllProcesses) {
+ Log.i(TAG, "Collecting RSS metrics for all processes.");
+ mProcessNames = getAllProcessNames();
+ } else if (mProcessNames.length > 0) {
+ Log.i(TAG, "Collecting RSS only for given list of process");
+ } else if (mProcessNames.length == 0) {
+ // No processes specified, just return empty map
+ return mRssMap;
+ }
+
+ FileWriter writer = new FileWriter(new File(mTestOutputFile), true);
+ for (String processName : mProcessNames) {
+ List<Integer> pids = new ArrayList<>();
+
+ long totalrss = 0;
+ // Collect required data
+ try {
+ pids = getPids(processName);
+
+ for (Integer pid: pids) {
+ String showmapOutput = execShowMap(processName, pid);
+ long rss = extractTotalRss(processName, showmapOutput);
+ // Track the total rss for the processes with the same process name.
+ totalrss += rss;
+ // Store showmap output into file. If there are more than one process
+ // with same name write the individual showmap associated with pid.
+ storeToFile(mTestOutputFile, processName, pid, showmapOutput, writer);
+ }
+ } catch (RuntimeException e) {
+ Log.e(TAG, e.getMessage(), e.getCause());
+ // Skip this process and continue with the next one
+ continue;
+ }
+
+ // Store metrics
+ mRssMap.put(constructKey(RSS_METRIC_PREFIX, processName), Long.toString(totalrss * 1024));
+ // Store the unique process count.
+ mRssMap.put(RSS_PROCESS_COUNT, Integer.toString(mProcessNames.length));
+ }
+ writer.close();
+ mRssMap.put(OUTPUT_FILE_PATH_KEY, mTestOutputFile);
+ } catch (RuntimeException e) {
+ Log.e(TAG, e.getMessage(), e.getCause());
+ } catch (IOException e) {
+ Log.e(TAG, String.format("Failed to write output file %s", mTestOutputFile), e);
+ }
+
+ return mRssMap;
+ }
+
+ @Override
+ public boolean stopCollecting() {
+ return true;
+ }
+
+ /**
+ * Set drop cache option.
+ *
+ * @param dropCacheOption drop pagecache (1), slab (2) or all (3) cache
+ * @return true on success, false if input option is invalid
+ */
+ public boolean setDropCacheOption(int dropCacheOption) {
+ // Valid values are 1..3
+ if (dropCacheOption < 1 || dropCacheOption > 3) {
+ return false;
+ }
+
+ mDropCacheOption = dropCacheOption;
+ return true;
+ }
+
+ /**
+ * Drops kernel memory cache.
+ *
+ * @param cacheOption drop pagecache (1), slab (2) or all (3) caches
+ */
+ private void dropCache(int cacheOption) throws RuntimeException {
+ try {
+ mUiDevice.executeShellCommand(String.format(DROP_CACHES_CMD, cacheOption));
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to drop caches", e);
+ }
+ }
+
+ /**
+ * Get pid's of the process with {@code processName} name.
+ *
+ * @param processName name of the process to get pid
+ * @return pid's of the specified process
+ */
+ private List<Integer> getPids(String processName) throws RuntimeException {
+ try {
+ String pidofOutput = mUiDevice.executeShellCommand(String.format(PIDOF_CMD, processName));
+
+ // Sample output for the process with more than 1 pid.
+ // Sample command : "pidof init"
+ // Sample output : 1 559
+ String[] pids = pidofOutput.split("\\s+");
+ List<Integer> pidList = new ArrayList<>();
+ for (String pid: pids) {
+ pidList.add(Integer.parseInt(pid.trim()));
+ }
+ return pidList;
+ } catch (IOException e) {
+ throw new RuntimeException(String.format("Unable to get pid of %s ", processName), e);
+ }
+ }
+
+ /**
+ * Executes showmap command for the process with {@code processName} name and {@code pid} pid.
+ *
+ * @param processName name of the process to run showmap for
+ * @param pid pid of the process to run showmap for
+ * @return the output of showmap command
+ */
+ private String execShowMap(String processName, long pid) throws IOException {
+ try {
+ return mUiDevice.executeShellCommand(String.format(SHOWMAP_CMD, pid));
+ } catch (IOException e) {
+ throw new RuntimeException(
+ String.format("Unable to execute showmap command for %s ", processName), e);
+ }
+ }
+
+ /**
+ * Extract total RSS from showmap command output for the process with {@code processName} name.
+ *
+ * @param processName name of the process to extract RSS for
+ * @param showmapOutput showmap command output
+ * @return total RSS of the process
+ */
+ private long extractTotalRss(String processName, String showmapOutput) throws RuntimeException {
+ try {
+ int pos = showmapOutput.lastIndexOf("----");
+ Scanner sc = new Scanner(showmapOutput.substring(pos));
+ sc.next();
+ sc.nextLong();
+ return sc.nextLong();
+ } catch (IndexOutOfBoundsException | InputMismatchException e) {
+ throw new RuntimeException(
+ String.format("Unexpected showmap format for %s ", processName), e);
+ }
+ }
+
+ /**
+ * Store test results for one process into file.
+ *
+ * @param fileName name of the file being written
+ * @param processName name of the process
+ * @param pid pid of the process
+ * @param showmapOutput showmap command output
+ * @param writer file writer to write the data
+ */
+ private void storeToFile(String fileName, String processName, long pid, String showmapOutput,
+ FileWriter writer) throws RuntimeException {
+ try {
+ writer.write(String.format(">>> %s (%d) <<<\n", processName, pid));
+ writer.write(showmapOutput);
+ writer.write('\n');
+ } catch (IOException e) {
+ throw new RuntimeException(String.format("Unable to write file %s ", fileName), e);
+ }
+ }
+
+ /**
+ * Enables RSS collection for all processes.
+ */
+ public void setAllProcesses() {
+ mCollectForAllProcesses = true;
+ }
+
+ /**
+ * Get all process names running in the system.
+ */
+ private String[] getAllProcessNames() {
+ Set<String> allProcessNames = new LinkedHashSet<>();
+ try {
+ String psOutput = mUiDevice.executeShellCommand(ALL_PROCESSES_CMD);
+ // Split the lines
+ String allProcesses[] = psOutput.split("\\n");
+ for (String invidualProcessDetails : allProcesses) {
+ Log.i(TAG, String.format("Process detail: %s", invidualProcessDetails));
+ // Sample process detail line
+ // system 603 1 41532 5396 SyS_epoll+ 0 S servicemanager
+ String processSplit[] = invidualProcessDetails.split("\\s+");
+ // Parse process name
+ String processName = processSplit[processSplit.length - 1].trim();
+ // Include the process name which are not enclosed in [].
+ if (!processName.startsWith("[") && !processName.endsWith("]")) {
+ // Skip the first (i.e header) line from "ps -A" output.
+ if (processName.equalsIgnoreCase("NAME")) {
+ continue;
+ }
+ Log.i(TAG, String.format("Including the process %s", processName));
+ allProcessNames.add(processName);
+ }
+ }
+ } catch (IOException ioe) {
+ throw new RuntimeException(
+ String.format("Unable execute all processes command %s ", ALL_PROCESSES_CMD),
+ ioe);
+ }
+ return allProcessNames.toArray(new String[0]);
+ }
+}
diff --git a/libraries/collectors-helper/memory/test/src/com/android/helpers/tests/RssSnapshotHelperTest.java b/libraries/collectors-helper/memory/test/src/com/android/helpers/tests/RssSnapshotHelperTest.java
new file mode 100644
index 00000000..6a1e1792
--- /dev/null
+++ b/libraries/collectors-helper/memory/test/src/com/android/helpers/tests/RssSnapshotHelperTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2019 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.helpers.tests;
+
+import static com.android.helpers.MetricUtility.constructKey;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import androidx.test.runner.AndroidJUnit4;
+import com.android.helpers.RssSnapshotHelper;
+import java.util.Map;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Android Unit tests for {@link RssSnapshotHelper}.
+ *
+ * To run:
+ * atest CollectorsHelperTest:com.android.helpers.tests.RssSnapshotHelperTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class RssSnapshotHelperTest {
+ private static final String TAG = RssSnapshotHelperTest.class.getSimpleName();
+
+ // Valid output file
+ private static final String VALID_OUTPUT_DIR = "/sdcard/test_results";
+ // Invalid output file (no permissions to write)
+ private static final String INVALID_OUTPUT_DIR = "/data/local/tmp";
+
+ // Lists of process names
+ private static final String[] EMPTY_PROCESS_LIST = {};
+ private static final String[] ONE_PROCESS_LIST = {"com.android.systemui"};
+ private static final String[] TWO_PROCESS_LIST = {"com.android.systemui", "system_server"};
+ private static final String[] NO_PROCESS_LIST = {null};
+
+ private RssSnapshotHelper mRssSnapshotHelper;
+
+ @Before
+ public void setUp() {
+ mRssSnapshotHelper = new RssSnapshotHelper();
+ }
+
+ /**
+ * Test start collecting returns false if the helper has not been properly set up.
+ */
+ @Test
+ public void testSetUpNotCalled() {
+ assertFalse(mRssSnapshotHelper.startCollecting());
+ }
+
+ /**
+ * Test invalid options for drop cache flag.
+ */
+ @Test
+ public void testInvalidDropCacheOptions() {
+ assertFalse(mRssSnapshotHelper.setDropCacheOption(-1));
+ assertFalse(mRssSnapshotHelper.setDropCacheOption(0));
+ assertFalse(mRssSnapshotHelper.setDropCacheOption(4));
+ }
+
+ /**
+ * Test invalid options for drop cache flag.
+ */
+ @Test
+ public void testValidDropCacheOptions() {
+ assertTrue(mRssSnapshotHelper.setDropCacheOption(1));
+ assertTrue(mRssSnapshotHelper.setDropCacheOption(2));
+ assertTrue(mRssSnapshotHelper.setDropCacheOption(3));
+ }
+
+ /**
+ * Test no metrics are sampled if process name is empty.
+ */
+ @Test
+ public void testEmptyProcessName() {
+ mRssSnapshotHelper.setUp(VALID_OUTPUT_DIR, EMPTY_PROCESS_LIST);
+ Map<String, String> metrics = mRssSnapshotHelper.getMetrics();
+ assertTrue(metrics.isEmpty());
+ }
+
+ /**
+ * Test sampling on a valid and running process.
+ */
+ @Test
+ public void testValidFile() {
+ mRssSnapshotHelper.setUp(VALID_OUTPUT_DIR, ONE_PROCESS_LIST);
+ assertTrue(mRssSnapshotHelper.startCollecting());
+ }
+
+ /**
+ * Test sampling on using an invalid output file.
+ */
+ @Test
+ public void testInvalidFile() {
+ mRssSnapshotHelper.setUp(INVALID_OUTPUT_DIR, ONE_PROCESS_LIST);
+ assertFalse(mRssSnapshotHelper.startCollecting());
+ }
+
+ /**
+ * Test getting metrics from one process.
+ */
+ @Test
+ public void testGetMetrics_OneProcess() {
+ testProcessList(ONE_PROCESS_LIST);
+ }
+
+ /**
+ * Test getting metrics from multiple processes process.
+ */
+ @Test
+ public void testGetMetrics_MultipleProcesses() {
+ testProcessList(TWO_PROCESS_LIST);
+ }
+
+ /**
+ * Test all process flag return more than 2 processes metrics atleast.
+ */
+ @Test
+ public void testGetMetrics_AllProcess() {
+ mRssSnapshotHelper.setUp(VALID_OUTPUT_DIR, NO_PROCESS_LIST);
+ mRssSnapshotHelper.setAllProcesses();
+ assertTrue(mRssSnapshotHelper.startCollecting());
+ Map<String, String> metrics = mRssSnapshotHelper.getMetrics();
+ assertTrue(metrics.size() > 2);
+ assertTrue(metrics.containsKey(RssSnapshotHelper.OUTPUT_FILE_PATH_KEY));
+
+ }
+
+
+ private void testProcessList(String... processNames) {
+ mRssSnapshotHelper.setUp(VALID_OUTPUT_DIR, processNames);
+ assertTrue(mRssSnapshotHelper.startCollecting());
+ Map<String, String> metrics = mRssSnapshotHelper.getMetrics();
+ assertFalse(metrics.isEmpty());
+ for (String processName : processNames) {
+ assertTrue(
+ metrics.containsKey(constructKey(RssSnapshotHelper.RSS_METRIC_PREFIX, processName)));
+ }
+ assertTrue(metrics.containsKey(RssSnapshotHelper.OUTPUT_FILE_PATH_KEY));
+ }
+}
diff --git a/libraries/device-collectors/src/main/java/android/device/collectors/RssSnapshotListener.java b/libraries/device-collectors/src/main/java/android/device/collectors/RssSnapshotListener.java
new file mode 100644
index 00000000..fc82512c
--- /dev/null
+++ b/libraries/device-collectors/src/main/java/android/device/collectors/RssSnapshotListener.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019 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 android.device.collectors;
+
+import android.device.collectors.annotations.OptionClass;
+import android.os.Bundle;
+import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+import com.android.helpers.RssSnapshotHelper;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A {@link RssSnapshotListener} that takes a snapshot of Rss sizes for the list of
+ * specified processes.
+ *
+ * Options:
+ * -e process-names [processNames] : a comma-separated list of processes
+ * -e drop-cache [pagecache | slab | all] : drop cache flag
+ * -e test-output-dir [path] : path to the output directory
+ */
+@OptionClass(alias = "rsssnapshot-collector")
+public class RssSnapshotListener extends BaseCollectionListener<String> {
+ private static final String TAG = RssSnapshotListener.class.getSimpleName();
+ private static final String DEFAULT_OUTPUT_DIR = "/sdcard/test_results";
+
+ @VisibleForTesting static final String PROCESS_SEPARATOR = ",";
+ @VisibleForTesting static final String PROCESS_NAMES_KEY = "process-names";
+ @VisibleForTesting static final String DROP_CACHE_KEY = "drop-cache";
+ @VisibleForTesting static final String OUTPUT_DIR_KEY = "test-output-dir";
+
+ private RssSnapshotHelper mRssSnapshotHelper = new RssSnapshotHelper();
+ private final Map<String, Integer> dropCacheValues = new HashMap<String, Integer>() {
+ {
+ put("pagecache", 1);
+ put("slab", 2);
+ put("all", 3);
+ }
+ };
+
+ public RssSnapshotListener() {
+ createHelperInstance(mRssSnapshotHelper);
+ }
+
+ /**
+ * Constructor to simulate receiving the instrumentation arguments. Should not be used except
+ * for testing.
+ */
+ @VisibleForTesting
+ public RssSnapshotListener(Bundle args, RssSnapshotHelper helper) {
+ super(args, helper);
+ mRssSnapshotHelper = helper;
+ createHelperInstance(mRssSnapshotHelper);
+ }
+
+ /**
+ * Adds the options for rss snapshot collector.
+ */
+ @Override
+ public void setupAdditionalArgs() {
+ Bundle args = getArgsBundle();
+ String testOutputDir = args.getString(OUTPUT_DIR_KEY, DEFAULT_OUTPUT_DIR);
+ // Collect for all processes if process list is empty or null.
+ String procsString = args.getString(PROCESS_NAMES_KEY);
+
+ String[] procs = null;
+ if (procsString == null || procsString.isEmpty()) {
+ mRssSnapshotHelper.setAllProcesses();
+ } else {
+ procs = procsString.split(PROCESS_SEPARATOR);
+ }
+
+ mRssSnapshotHelper.setUp(testOutputDir, procs);
+
+ String dropCacheValue = args.getString(DROP_CACHE_KEY);
+ if (dropCacheValue != null) {
+ if (dropCacheValues.containsKey(dropCacheValue)) {
+ mRssSnapshotHelper.setDropCacheOption(dropCacheValues.get(dropCacheValue));
+ } else {
+ Log.e(TAG, "Value for \"" + DROP_CACHE_KEY + "\" parameter is invalid");
+ return;
+ }
+ }
+ }
+}
diff --git a/libraries/device-collectors/src/test/java/android/device/collectors/RssSnapshotListenerTest.java b/libraries/device-collectors/src/test/java/android/device/collectors/RssSnapshotListenerTest.java
new file mode 100644
index 00000000..883a0588
--- /dev/null
+++ b/libraries/device-collectors/src/test/java/android/device/collectors/RssSnapshotListenerTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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 android.device.collectors;
+
+import static android.device.collectors.RssSnapshotListener.DROP_CACHE_KEY;
+import static android.device.collectors.RssSnapshotListener.OUTPUT_DIR_KEY;
+import static android.device.collectors.RssSnapshotListener.PROCESS_NAMES_KEY;
+import static android.device.collectors.RssSnapshotListener.PROCESS_SEPARATOR;
+import static org.mockito.Mockito.verify;
+
+import android.app.Instrumentation;
+import android.os.Bundle;
+import androidx.test.runner.AndroidJUnit4;
+import com.android.helpers.RssSnapshotHelper;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Android Unit tests for {@link RssSnapshotListener}.
+ *
+ * To run:
+ * atest CollectorDeviceLibTest:android.device.collectors.RssSnapshotListenerTest
+ */
+@RunWith(AndroidJUnit4.class)
+public class RssSnapshotListenerTest {
+ @Mock private Instrumentation mInstrumentation;
+ @Mock private RssSnapshotHelper mRssSnapshotHelper;
+
+ private RssSnapshotListener mListener;
+ private Description mRunDesc;
+
+ private static final String VALID_OUTPUT_DIR = "/data/local/tmp";
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mRunDesc = Description.createSuiteDescription("run");
+ }
+
+ private RssSnapshotListener initListener(Bundle b) {
+ RssSnapshotListener listener = new RssSnapshotListener(b, mRssSnapshotHelper);
+ listener.setInstrumentation(mInstrumentation);
+ return listener;
+ }
+
+ @Test
+ public void testHelperReceivesProcessNames() throws Exception {
+ Bundle b = new Bundle();
+ b.putString(PROCESS_NAMES_KEY, "process1" + PROCESS_SEPARATOR + "process2");
+ b.putString(OUTPUT_DIR_KEY, VALID_OUTPUT_DIR);
+
+ mListener = initListener(b);
+
+ mListener.testRunStarted(mRunDesc);
+
+ verify(mRssSnapshotHelper).setUp(VALID_OUTPUT_DIR, "process1", "process2");
+ }
+
+ @Test
+ public void testAdditionalOptions() throws Exception {
+ Bundle b = new Bundle();
+ b.putString(PROCESS_NAMES_KEY, "process1");
+ b.putString(OUTPUT_DIR_KEY, VALID_OUTPUT_DIR);
+ b.putString(DROP_CACHE_KEY, "all");
+ mListener = initListener(b);
+
+ mListener.testRunStarted(mRunDesc);
+
+ verify(mRssSnapshotHelper).setUp(VALID_OUTPUT_DIR, "process1");
+ // DROP_CACHE_KEY values: "pagecache" = 1, "slab" = 2, "all" = 3
+ verify(mRssSnapshotHelper).setDropCacheOption(3);
+ }
+}