Merge "Extend & refactor Statsd TestDrive tool." into rvc-dev

This commit is contained in:
TreeHugger Robot
2020-04-28 06:45:05 +00:00
committed by Android (Google) Code Review
7 changed files with 794 additions and 148 deletions

View File

@@ -11,9 +11,8 @@ java_binary_host {
],
}
java_binary_host {
name: "statsd_testdrive",
manifest: "testdrive_manifest.txt",
java_library_host {
name: "statsd_testdrive_lib",
srcs: [
"src/com/android/statsd/shelltools/testdrive/*.java",
"src/com/android/statsd/shelltools/Utils.java",
@@ -22,4 +21,26 @@ java_binary_host {
"platformprotos",
"guava",
],
}
}
java_binary_host {
name: "statsd_testdrive",
manifest: "testdrive_manifest.txt",
static_libs: [
"statsd_testdrive_lib",
],
}
java_test_host {
name: "statsd_testdrive_test",
test_suites: ["general-tests"],
srcs: ["test/com/android/statsd/shelltools/testdrive/*.java"],
static_libs: [
"statsd_testdrive_lib",
"junit",
"platformprotos",
"guava",
],
}

View File

@@ -0,0 +1,8 @@
{
"presubmit": [
{
"name": "statsd_testdrive_test",
"host": true
}
]
}

View File

@@ -229,4 +229,56 @@ public class Utils {
}
return null;
}
/**
* Returns ANDROID_SERIAL environment variable, or null if that is undefined or unavailable.
* @param logger Destination of error messages.
* @return String value of ANDROID_SERIAL environment variable, or null.
*/
public static String getDefaultDevice(Logger logger) {
try {
return System.getenv("ANDROID_SERIAL");
} catch (Exception ex) {
logger.log(Level.SEVERE, "Failed to check ANDROID_SERIAL environment variable.",
ex);
}
return null;
}
/**
* Returns the device to use if one can be deduced, or null.
* @param device Command-line specified device, or null.
* @param connectedDevices List of all connected devices.
* @param defaultDevice Environment-variable specified device, or null.
* @param logger Destination of error messages.
* @return Device to use, or null.
*/
public static String chooseDevice(String device, List<String> connectedDevices,
String defaultDevice, Logger logger) {
if (connectedDevices == null || connectedDevices.isEmpty()) {
logger.severe("No connected device.");
return null;
}
if (device != null) {
if (connectedDevices.contains(device)) {
return device;
}
logger.severe("Device not connected: " + device);
return null;
}
if (connectedDevices.size() == 1) {
return connectedDevices.get(0);
}
if (defaultDevice != null) {
if (connectedDevices.contains(defaultDevice)) {
return defaultDevice;
} else {
logger.severe("ANDROID_SERIAL device is not connected: " + defaultDevice);
return null;
}
}
logger.severe("More than one device is connected. Choose one"
+ " with -s DEVICE_SERIAL or environment variable ANDROID_SERIAL.");
return null;
}
}

View File

@@ -27,7 +27,6 @@ import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
@@ -112,17 +111,9 @@ public class LocalDrive {
}
List<String> connectedDevices = Utils.getDeviceSerials(sLogger);
if (connectedDevices == null || connectedDevices.size() == 0) {
sLogger.log(Level.SEVERE, "No device connected.");
return;
}
if (connectedDevices.size() == 1 && deviceSerial == null) {
deviceSerial = connectedDevices.get(0);
}
deviceSerial = Utils.chooseDevice(deviceSerial, connectedDevices,
Utils.getDefaultDevice(sLogger), sLogger);
if (deviceSerial == null) {
sLogger.log(Level.SEVERE, "More than one devices connected. Please specify"
+ " with -s DEVICE_SERIAL");
return;
}

View File

@@ -15,6 +15,7 @@
*/
package com.android.statsd.shelltools.testdrive;
import com.android.internal.os.StatsdConfigProto;
import com.android.internal.os.StatsdConfigProto.AtomMatcher;
import com.android.internal.os.StatsdConfigProto.EventMetric;
import com.android.internal.os.StatsdConfigProto.FieldFilter;
@@ -29,6 +30,7 @@ import com.android.os.StatsLog.ConfigMetricsReportList;
import com.android.os.StatsLog.StatsLogReport;
import com.android.statsd.shelltools.Utils;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.io.Files;
import java.io.File;
@@ -39,6 +41,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -73,179 +76,269 @@ public class TestDrive {
};
private static final Logger LOGGER = Logger.getLogger(TestDrive.class.getName());
private String mAdditionalAllowedPackage;
private String mDeviceSerial;
private final Set<Long> mTrackedMetrics = new HashSet<>();
@VisibleForTesting
String mDeviceSerial = null;
public static void main(String[] args) {
final Configuration configuration = new Configuration();
TestDrive testDrive = new TestDrive();
Set<Integer> trackedAtoms = new HashSet<>();
Utils.setUpLogger(LOGGER, false);
String remoteConfigPath = null;
if (!testDrive.processArgs(configuration, args,
Utils.getDeviceSerials(LOGGER), Utils.getDefaultDevice(LOGGER))) {
return;
}
final ConfigMetricsReportList reports = testDrive.testDriveAndGetReports(
configuration.createConfig(), configuration.hasPulledAtoms(),
configuration.hasPushedAtoms());
if (reports != null) {
configuration.dumpMetrics(reports);
}
}
boolean processArgs(Configuration configuration, String[] args, List<String> connectedDevices,
String defaultDevice) {
if (args.length < 1) {
LOGGER.log(Level.SEVERE, "Usage: ./test_drive [-p additional_allowed_package] "
+ "[-s DEVICE_SERIAL_NUMBER]"
LOGGER.severe("Usage: ./test_drive [-one] "
+ "[-p additional_allowed_package] "
+ "[-s DEVICE_SERIAL_NUMBER] "
+ "<atomId1> <atomId2> ... <atomIdN>");
return;
return false;
}
List<String> connectedDevices = Utils.getDeviceSerials(LOGGER);
if (connectedDevices == null || connectedDevices.size() == 0) {
LOGGER.log(Level.SEVERE, "No device connected.");
return;
}
int arg_index = 0;
while (arg_index < args.length) {
String arg = args[arg_index];
if (arg.equals("-p")) {
testDrive.mAdditionalAllowedPackage = args[++arg_index];
} else if (arg.equals("-s")) {
testDrive.mDeviceSerial = args[++arg_index];
int first_arg = 0;
// Consume all flags, which must precede all atoms
for (; first_arg < args.length; ++first_arg) {
String arg = args[first_arg];
int remaining_args = args.length - first_arg;
if (remaining_args >= 2 && arg.equals("-one")) {
LOGGER.info("Creating one event metric to catch all pushed atoms.");
configuration.mOnePushedAtomEvent = true;
} else if (remaining_args >= 3 && arg.equals("-p")) {
configuration.mAdditionalAllowedPackage = args[++first_arg];
} else if (remaining_args >= 3 && arg.equals("-s")) {
mDeviceSerial = args[++first_arg];
} else {
break;
break; // Found the atom list
}
arg_index++;
}
if (connectedDevices.size() == 1 && testDrive.mDeviceSerial == null) {
testDrive.mDeviceSerial = connectedDevices.get(0);
mDeviceSerial = Utils.chooseDevice(mDeviceSerial, connectedDevices, defaultDevice, LOGGER);
if (mDeviceSerial == null) {
return false;
}
if (testDrive.mDeviceSerial == null) {
LOGGER.log(Level.SEVERE, "More than one devices connected. Please specify"
+ " with -s DEVICE_SERIAL");
return;
}
for (int i = arg_index; i < args.length; i++) {
for ( ; first_arg < args.length; ++first_arg) {
String atom = args[first_arg];
try {
int atomId = Integer.valueOf(args[i]);
if (Atom.getDescriptor().findFieldByNumber(atomId) == null) {
LOGGER.log(Level.SEVERE, "No such atom found: " + args[i]);
continue;
}
trackedAtoms.add(atomId);
configuration.addAtom(Integer.valueOf(atom));
} catch (NumberFormatException e) {
LOGGER.log(Level.SEVERE, "Bad atom id provided: " + args[i]);
continue;
LOGGER.severe("Bad atom id provided: " + atom);
}
}
return configuration.hasPulledAtoms() || configuration.hasPushedAtoms();
}
private ConfigMetricsReportList testDriveAndGetReports(StatsdConfig config,
boolean hasPulledAtoms, boolean hasPushedAtoms) {
if (config == null) {
LOGGER.severe("Failed to create valid config.");
return null;
}
String remoteConfigPath = null;
try {
StatsdConfig config = testDrive.createConfig(trackedAtoms);
if (config == null) {
LOGGER.log(Level.SEVERE, "Failed to create valid config.");
return;
}
remoteConfigPath = testDrive.pushConfig(config, testDrive.mDeviceSerial);
LOGGER.info("Pushed the following config to statsd:");
remoteConfigPath = pushConfig(config, mDeviceSerial);
LOGGER.info("Pushed the following config to statsd on device '" + mDeviceSerial
+ "':");
LOGGER.info(config.toString());
if (!hasPulledAtom(trackedAtoms)) {
if (hasPushedAtoms) {
LOGGER.info("Now please play with the device to trigger the event.");
}
if (!hasPulledAtoms) {
LOGGER.info(
"Now please play with the device to trigger the event. All events should "
+ "be dumped after 1 min ...");
"All events should be dumped after 1 min ...");
Thread.sleep(60_000);
} else {
LOGGER.info("Now wait for 1.5 minutes ...");
LOGGER.info("All events should be dumped after 1.5 minutes ...");
Thread.sleep(15_000);
Utils.logAppBreadcrumb(0, 0, LOGGER, testDrive.mDeviceSerial);
Utils.logAppBreadcrumb(0, 0, LOGGER, mDeviceSerial);
Thread.sleep(75_000);
}
testDrive.dumpMetrics();
return Utils.getReportList(CONFIG_ID, true, false, LOGGER,
mDeviceSerial);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Failed to test drive: " + e.getMessage(), e);
} finally {
testDrive.removeConfig(testDrive.mDeviceSerial);
removeConfig(mDeviceSerial);
if (remoteConfigPath != null) {
try {
Utils.runCommand(null, LOGGER,
"adb", "-s", testDrive.mDeviceSerial, "shell", "rm", remoteConfigPath);
"adb", "-s", mDeviceSerial, "shell", "rm",
remoteConfigPath);
} catch (Exception e) {
LOGGER.log(Level.WARNING,
"Unable to remove remote config file: " + remoteConfigPath, e);
}
}
}
return null;
}
private void dumpMetrics() throws Exception {
ConfigMetricsReportList reportList = Utils.getReportList(CONFIG_ID, true, false, LOGGER,
mDeviceSerial);
// We may get multiple reports. Take the last one.
ConfigMetricsReport report = reportList.getReports(reportList.getReportsCount() - 1);
for (StatsLogReport statsLog : report.getMetricsList()) {
if (mTrackedMetrics.contains(statsLog.getMetricId())) {
LOGGER.info(statsLog.toString());
static class Configuration {
boolean mOnePushedAtomEvent = false;
@VisibleForTesting
Set<Integer> mPushedAtoms = new TreeSet<>();
@VisibleForTesting
Set<Integer> mPulledAtoms = new TreeSet<>();
@VisibleForTesting
String mAdditionalAllowedPackage = null;
private final Set<Long> mTrackedMetrics = new HashSet<>();
private void dumpMetrics(ConfigMetricsReportList reportList) {
// We may get multiple reports. Take the last one.
ConfigMetricsReport report = reportList.getReports(reportList.getReportsCount() - 1);
for (StatsLogReport statsLog : report.getMetricsList()) {
if (isTrackedMetric(statsLog.getMetricId())) {
LOGGER.info(statsLog.toString());
}
}
}
}
private StatsdConfig createConfig(Set<Integer> atomIds) {
long metricId = METRIC_ID_BASE;
long atomMatcherId = ATOM_MATCHER_ID_BASE;
ArrayList<String> allowedSources = new ArrayList<>();
Collections.addAll(allowedSources, ALLOWED_LOG_SOURCES);
if (mAdditionalAllowedPackage != null) {
allowedSources.add(mAdditionalAllowedPackage);
boolean isTrackedMetric(long metricId) {
return mTrackedMetrics.contains(metricId);
}
StatsdConfig.Builder builder = StatsdConfig.newBuilder();
builder
.addAllAllowedLogSource(allowedSources)
.addAllDefaultPullPackages(Arrays.asList(DEFAULT_PULL_SOURCES))
.addPullAtomPackages(PullAtomPackages.newBuilder()
.setAtomId(Atom.GPU_STATS_GLOBAL_INFO_FIELD_NUMBER)
.addPackages("AID_GPU_SERVICE"))
.addPullAtomPackages(PullAtomPackages.newBuilder()
.setAtomId(Atom.GPU_STATS_APP_INFO_FIELD_NUMBER)
.addPackages("AID_GPU_SERVICE"))
.addPullAtomPackages(PullAtomPackages.newBuilder()
.setAtomId(Atom.TRAIN_INFO_FIELD_NUMBER)
.addPackages("AID_STATSD"))
.setHashStringsInMetricReport(false);
if (hasPulledAtom(atomIds)) {
builder.addAtomMatcher(
createAtomMatcher(
Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER, APP_BREADCRUMB_MATCHER_ID));
static boolean isPulledAtom(int atomId) {
return atomId >= PULL_ATOM_START && atomId <= MAX_PLATFORM_ATOM_TAG
|| atomId >= VENDOR_PULLED_ATOM_START_TAG;
}
for (int atomId : atomIds) {
if (isPulledAtom(atomId)) {
void addAtom(Integer atom) {
if (Atom.getDescriptor().findFieldByNumber(atom) == null) {
LOGGER.severe("No such atom found: " + atom);
return;
}
if (isPulledAtom(atom)) {
mPulledAtoms.add(atom);
} else {
mPushedAtoms.add(atom);
}
}
private boolean hasPulledAtoms() {
return !mPulledAtoms.isEmpty();
}
private boolean hasPushedAtoms() {
return !mPushedAtoms.isEmpty();
}
StatsdConfig createConfig() {
long metricId = METRIC_ID_BASE;
long atomMatcherId = ATOM_MATCHER_ID_BASE;
StatsdConfig.Builder builder = baseBuilder();
if (hasPulledAtoms()) {
builder.addAtomMatcher(
createAtomMatcher(
Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER,
APP_BREADCRUMB_MATCHER_ID));
}
for (int atomId : mPulledAtoms) {
builder.addAtomMatcher(createAtomMatcher(atomId, atomMatcherId));
GaugeMetric.Builder gaugeMetricBuilder = GaugeMetric.newBuilder();
gaugeMetricBuilder
.setId(metricId)
.setWhat(atomMatcherId)
.setTriggerEvent(APP_BREADCRUMB_MATCHER_ID)
.setGaugeFieldsFilter(FieldFilter.newBuilder().setIncludeAll(true).build())
.setBucket(TimeUnit.ONE_MINUTE)
.setSamplingType(GaugeMetric.SamplingType.FIRST_N_SAMPLES)
.setMaxNumGaugeAtomsPerBucket(100);
.setId(metricId)
.setWhat(atomMatcherId)
.setTriggerEvent(APP_BREADCRUMB_MATCHER_ID)
.setGaugeFieldsFilter(FieldFilter.newBuilder().setIncludeAll(true).build())
.setBucket(TimeUnit.ONE_MINUTE)
.setSamplingType(GaugeMetric.SamplingType.FIRST_N_SAMPLES)
.setMaxNumGaugeAtomsPerBucket(100);
builder.addGaugeMetric(gaugeMetricBuilder.build());
} else {
EventMetric.Builder eventMetricBuilder = EventMetric.newBuilder();
eventMetricBuilder
.setId(metricId)
.setWhat(atomMatcherId);
builder.addEventMetric(eventMetricBuilder.build());
builder.addAtomMatcher(createAtomMatcher(atomId, atomMatcherId));
atomMatcherId++;
mTrackedMetrics.add(metricId++);
}
atomMatcherId++;
mTrackedMetrics.add(metricId++);
}
return builder.build();
}
private static AtomMatcher createAtomMatcher(int atomId, long matcherId) {
AtomMatcher.Builder atomMatcherBuilder = AtomMatcher.newBuilder();
atomMatcherBuilder
.setId(matcherId)
.setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder().setAtomId(atomId));
return atomMatcherBuilder.build();
// A simple atom matcher for each pushed atom.
List<AtomMatcher> simpleAtomMatchers = new ArrayList<>();
for (int atomId : mPushedAtoms) {
final AtomMatcher atomMatcher = createAtomMatcher(atomId, atomMatcherId++);
simpleAtomMatchers.add(atomMatcher);
builder.addAtomMatcher(atomMatcher);
}
if (mOnePushedAtomEvent) {
// Create a union event metric, using an matcher that matches all pulled atoms.
AtomMatcher unionAtomMatcher = createUnionMatcher(simpleAtomMatchers,
atomMatcherId);
builder.addAtomMatcher(unionAtomMatcher);
EventMetric.Builder eventMetricBuilder = EventMetric.newBuilder();
eventMetricBuilder.setId(metricId).setWhat(unionAtomMatcher.getId());
builder.addEventMetric(eventMetricBuilder.build());
mTrackedMetrics.add(metricId++);
} else {
// Create multiple event metrics, one per pulled atom.
for (AtomMatcher atomMatcher : simpleAtomMatchers) {
EventMetric.Builder eventMetricBuilder = EventMetric.newBuilder();
eventMetricBuilder
.setId(metricId)
.setWhat(atomMatcher.getId());
builder.addEventMetric(eventMetricBuilder.build());
mTrackedMetrics.add(metricId++);
}
}
return builder.build();
}
private static AtomMatcher createAtomMatcher(int atomId, long matcherId) {
AtomMatcher.Builder atomMatcherBuilder = AtomMatcher.newBuilder();
atomMatcherBuilder
.setId(matcherId)
.setSimpleAtomMatcher(SimpleAtomMatcher.newBuilder().setAtomId(atomId));
return atomMatcherBuilder.build();
}
private AtomMatcher createUnionMatcher(List<AtomMatcher> simpleAtomMatchers,
long atomMatcherId) {
AtomMatcher.Combination.Builder combinationBuilder =
AtomMatcher.Combination.newBuilder();
combinationBuilder.setOperation(StatsdConfigProto.LogicalOperation.OR);
for (AtomMatcher matcher : simpleAtomMatchers) {
combinationBuilder.addMatcher(matcher.getId());
}
AtomMatcher.Builder atomMatcherBuilder = AtomMatcher.newBuilder();
atomMatcherBuilder.setId(atomMatcherId).setCombination(combinationBuilder.build());
return atomMatcherBuilder.build();
}
private StatsdConfig.Builder baseBuilder() {
ArrayList<String> allowedSources = new ArrayList<>();
Collections.addAll(allowedSources, ALLOWED_LOG_SOURCES);
if (mAdditionalAllowedPackage != null) {
allowedSources.add(mAdditionalAllowedPackage);
}
return StatsdConfig.newBuilder()
.addAllAllowedLogSource(allowedSources)
.addAllDefaultPullPackages(Arrays.asList(DEFAULT_PULL_SOURCES))
.addPullAtomPackages(PullAtomPackages.newBuilder()
.setAtomId(Atom.GPU_STATS_GLOBAL_INFO_FIELD_NUMBER)
.addPackages("AID_GPU_SERVICE"))
.addPullAtomPackages(PullAtomPackages.newBuilder()
.setAtomId(Atom.GPU_STATS_APP_INFO_FIELD_NUMBER)
.addPackages("AID_GPU_SERVICE"))
.addPullAtomPackages(PullAtomPackages.newBuilder()
.setAtomId(Atom.TRAIN_INFO_FIELD_NUMBER)
.addPackages("AID_STATSD"))
.setHashStringsInMetricReport(false);
}
}
private static String pushConfig(StatsdConfig config, String deviceSerial)
@@ -267,21 +360,7 @@ public class TestDrive {
Utils.runCommand(null, LOGGER, "adb", "-s", deviceSerial,
"shell", Utils.CMD_REMOVE_CONFIG, String.valueOf(CONFIG_ID));
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Failed to remove config: " + e.getMessage());
LOGGER.severe("Failed to remove config: " + e.getMessage());
}
}
private static boolean isPulledAtom(int atomId) {
return atomId >= PULL_ATOM_START && atomId <= MAX_PLATFORM_ATOM_TAG
|| atomId >= VENDOR_PULLED_ATOM_START_TAG;
}
private static boolean hasPulledAtom(Set<Integer> atoms) {
for (Integer i : atoms) {
if (isPulledAtom(i)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,326 @@
/*
* Copyright (C) 2020 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.statsd.shelltools.testdrive;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import com.android.internal.os.StatsdConfigProto;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
import com.android.os.AtomsProto;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Tests for {@link TestDrive}
*/
public class ConfigurationTest {
private StatsdConfigProto.AtomMatcher findAndRemoveAtomMatcherById(
List<StatsdConfigProto.AtomMatcher> atomMatchers, long id) {
int numMatches = 0;
StatsdConfigProto.AtomMatcher match = null;
for (StatsdConfigProto.AtomMatcher atomMatcher : atomMatchers) {
if (id == atomMatcher.getId()) {
++numMatches;
match = atomMatcher;
}
}
if (numMatches == 1) {
atomMatchers.remove(match);
return match;
}
return null; // Too many, or not found
}
private final TestDrive.Configuration mConfiguration = new TestDrive.Configuration();
@Test
public void testOnePushed() {
final int atom = 90;
assertFalse(TestDrive.Configuration.isPulledAtom(atom));
mConfiguration.addAtom(atom);
StatsdConfig config = mConfiguration.createConfig();
//event_metric {
// id: 1111
// what: 1234567
//}
//atom_matcher {
// id: 1234567
// simple_atom_matcher {
// atom_id: 90
// }
//}
assertEquals(1, config.getEventMetricCount());
assertEquals(0, config.getGaugeMetricCount());
assertTrue(mConfiguration.isTrackedMetric(config.getEventMetric(0).getId()));
final List<StatsdConfigProto.AtomMatcher> atomMatchers =
new ArrayList<>(config.getAtomMatcherList());
assertEquals(atom,
findAndRemoveAtomMatcherById(atomMatchers, config.getEventMetric(0).getWhat())
.getSimpleAtomMatcher().getAtomId());
assertEquals(0, atomMatchers.size());
}
@Test
public void testOnePulled() {
final int atom = 10022;
assertTrue(TestDrive.Configuration.isPulledAtom(atom));
mConfiguration.addAtom(atom);
StatsdConfig config = mConfiguration.createConfig();
//gauge_metric {
// id: 1111
// what: 1234567
// gauge_fields_filter {
// include_all: true
// }
// bucket: ONE_MINUTE
// sampling_type: FIRST_N_SAMPLES
// max_num_gauge_atoms_per_bucket: 100
// trigger_event: 1111111
//}
//atom_matcher {
// id: 1111111
// simple_atom_matcher {
// atom_id: 47
// }
//}
//atom_matcher {
// id: 1234567
// simple_atom_matcher {
// atom_id: 10022
// }
//}
assertEquals(0, config.getEventMetricCount());
assertEquals(1, config.getGaugeMetricCount());
assertTrue(mConfiguration.isTrackedMetric(config.getGaugeMetric(0).getId()));
final StatsdConfigProto.GaugeMetric gaugeMetric = config.getGaugeMetric(0);
assertTrue(gaugeMetric.getGaugeFieldsFilter().getIncludeAll());
final List<StatsdConfigProto.AtomMatcher> atomMatchers =
new ArrayList<>(config.getAtomMatcherList());
assertEquals(atom,
findAndRemoveAtomMatcherById(atomMatchers, gaugeMetric.getWhat())
.getSimpleAtomMatcher().getAtomId());
assertEquals(AtomsProto.Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER,
findAndRemoveAtomMatcherById(atomMatchers, gaugeMetric.getTriggerEvent())
.getSimpleAtomMatcher().getAtomId());
assertEquals(0, atomMatchers.size());
}
@Test
public void testOnePulledTwoPushed() {
final int pulledAtom = 10022;
assertTrue(TestDrive.Configuration.isPulledAtom(pulledAtom));
mConfiguration.addAtom(pulledAtom);
Integer[] pushedAtoms = new Integer[]{244, 245};
for (int atom : pushedAtoms) {
assertFalse(TestDrive.Configuration.isPulledAtom(atom));
mConfiguration.addAtom(atom);
}
StatsdConfig config = mConfiguration.createConfig();
// event_metric {
// id: 1111
// what: 1234567
// }
// event_metric {
// id: 1112
// what: 1234568
// }
// gauge_metric {
// id: 1114
// what: 1234570
// gauge_fields_filter {
// include_all: true
// }
// bucket: ONE_MINUTE
// sampling_type: FIRST_N_SAMPLES
// max_num_gauge_atoms_per_bucket: 100
// trigger_event: 1111111
// }
// atom_matcher {
// id: 1111111
// simple_atom_matcher {
// atom_id: 47
// }
// }
// atom_matcher {
// id: 1234567
// simple_atom_matcher {
// atom_id: 244
// }
// }
// atom_matcher {
// id: 1234568
// simple_atom_matcher {
// atom_id: 245
// }
// }
// atom_matcher {
// id: 1234570
// simple_atom_matcher {
// atom_id: 10022
// }
// }
assertEquals(2, config.getEventMetricCount());
assertEquals(1, config.getGaugeMetricCount());
final StatsdConfigProto.GaugeMetric gaugeMetric = config.getGaugeMetric(0);
assertTrue(mConfiguration.isTrackedMetric(gaugeMetric.getId()));
assertTrue(gaugeMetric.getGaugeFieldsFilter().getIncludeAll());
for (StatsdConfigProto.EventMetric eventMetric : config.getEventMetricList()) {
assertTrue(mConfiguration.isTrackedMetric(eventMetric.getId()));
}
final List<StatsdConfigProto.AtomMatcher> atomMatchers =
new ArrayList<>(config.getAtomMatcherList());
assertEquals(pulledAtom, findAndRemoveAtomMatcherById(atomMatchers, gaugeMetric.getWhat())
.getSimpleAtomMatcher().getAtomId());
assertEquals(AtomsProto.Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER,
findAndRemoveAtomMatcherById(atomMatchers, gaugeMetric.getTriggerEvent())
.getSimpleAtomMatcher().getAtomId());
Integer[] actualAtoms = new Integer[]{
findAndRemoveAtomMatcherById(atomMatchers, config.getEventMetric(0).getWhat())
.getSimpleAtomMatcher().getAtomId(),
findAndRemoveAtomMatcherById(atomMatchers, config.getEventMetric(1).getWhat())
.getSimpleAtomMatcher().getAtomId()};
Arrays.sort(actualAtoms);
assertArrayEquals(pushedAtoms, actualAtoms);
assertEquals(0, atomMatchers.size());
}
@Test
public void testOnePulledTwoPushedTogether() {
mConfiguration.mOnePushedAtomEvent = true; // Use one event grabbing all pushed atoms
final int pulledAtom = 10022;
assertTrue(TestDrive.Configuration.isPulledAtom(pulledAtom));
mConfiguration.addAtom(pulledAtom);
Integer[] pushedAtoms = new Integer[]{244, 245};
for (int atom : pushedAtoms) {
assertFalse(TestDrive.Configuration.isPulledAtom(atom));
mConfiguration.addAtom(atom);
}
StatsdConfig config = mConfiguration.createConfig();
// event_metric {
// id: 1112
// what: 1234570
// }
// gauge_metric {
// id: 1111
// what: 1234567
// gauge_fields_filter {
// include_all: true
// }
// bucket: ONE_MINUTE
// sampling_type: FIRST_N_SAMPLES
// max_num_gauge_atoms_per_bucket: 100
// trigger_event: 1111111
// }
// atom_matcher {
// id: 1111111
// simple_atom_matcher {
// atom_id: 47
// }
// }
// atom_matcher {
// id: 1234567
// simple_atom_matcher {
// atom_id: 10022
// }
// }
// atom_matcher {
// id: 1234568
// simple_atom_matcher {
// atom_id: 244
// }
// }
// atom_matcher {
// id: 1234569
// simple_atom_matcher {
// atom_id: 245
// }
// }
// atom_matcher {
// id: 1234570
// combination {
// operation: OR
// matcher: 1234568
// matcher: 1234569
// }
// }
assertEquals(1, config.getEventMetricCount());
assertEquals(1, config.getGaugeMetricCount());
final StatsdConfigProto.GaugeMetric gaugeMetric = config.getGaugeMetric(0);
assertTrue(mConfiguration.isTrackedMetric(gaugeMetric.getId()));
assertTrue(gaugeMetric.getGaugeFieldsFilter().getIncludeAll());
StatsdConfigProto.EventMetric eventMetric = config.getEventMetric(0);
assertTrue(mConfiguration.isTrackedMetric(eventMetric.getId()));
final List<StatsdConfigProto.AtomMatcher> atomMatchers =
new ArrayList<>(config.getAtomMatcherList());
assertEquals(pulledAtom, findAndRemoveAtomMatcherById(atomMatchers, gaugeMetric.getWhat())
.getSimpleAtomMatcher().getAtomId());
assertEquals(AtomsProto.Atom.APP_BREADCRUMB_REPORTED_FIELD_NUMBER,
findAndRemoveAtomMatcherById(atomMatchers, gaugeMetric.getTriggerEvent())
.getSimpleAtomMatcher().getAtomId());
StatsdConfigProto.AtomMatcher unionMatcher = findAndRemoveAtomMatcherById(atomMatchers,
eventMetric.getWhat());
assertNotNull(unionMatcher.getCombination());
assertEquals(2, unionMatcher.getCombination().getMatcherCount());
Integer[] actualAtoms = new Integer[]{
findAndRemoveAtomMatcherById(atomMatchers,
unionMatcher.getCombination().getMatcher(0))
.getSimpleAtomMatcher().getAtomId(),
findAndRemoveAtomMatcherById(atomMatchers,
unionMatcher.getCombination().getMatcher(1))
.getSimpleAtomMatcher().getAtomId()};
Arrays.sort(actualAtoms);
assertArrayEquals(pushedAtoms, actualAtoms);
assertEquals(0, atomMatchers.size());
}
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright (C) 2020 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.statsd.shelltools.testdrive;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* Tests for {@link TestDrive}
*/
@RunWith(Parameterized.class)
public class TestDriveTest {
/**
* Expected results of a single iteration of the paramerized test.
*/
static class Expect {
public boolean success;
public Integer[] atoms;
public boolean onePushedAtomEvent;
public String extraPackage;
public String target;
static Expect success(Integer... atoms) {
return new Expect(true, atoms, false, null,
TARGET);
}
Expect(boolean success, Integer[] atoms, boolean onePushedAtomEvent, String extraPackage,
String target) {
this.success = success;
this.atoms = atoms;
this.onePushedAtomEvent = onePushedAtomEvent;
this.extraPackage = extraPackage;
this.target = target;
}
static final Expect FAILURE = new Expect(false, null,
false, null, null);
Expect onePushedAtomEvent() {
this.onePushedAtomEvent = true;
return this;
}
Expect extraPackage() {
this.extraPackage = TestDriveTest.PACKAGE;
return this;
}
}
@Parameterized.Parameter(0)
public String[] mArgs;
@Parameterized.Parameter(1)
public List<String> mConnectedDevices;
@Parameterized.Parameter(2)
public String mDefaultDevice;
@Parameterized.Parameter(3)
public Expect mExpect;
private static final String TARGET = "target";
private static final List<String> TARGET_AND_OTHER = Arrays.asList("otherDevice",
TARGET);
private static final List<String> TWO_OTHER_DEVICES = Arrays.asList(
"other1", "other2");
private static final List<String> TARGET_ONLY = Collections.singletonList(TARGET);
private static final List<String> NOT_TARGET = Collections.singletonList("other");
private static final List<String> NO_DEVICES = Collections.emptyList();
private static final String PACKAGE = "extraPackage";
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(
new Object[]{new String[]{}, null, null,
Expect.FAILURE}, // Usage explanation
new Object[]{new String[]{"244", "245"}, null, null,
Expect.FAILURE}, // Failure looking up connected devices
new Object[]{new String[]{"244", "245"}, NO_DEVICES, null,
Expect.FAILURE}, // No connected devices
new Object[]{new String[]{"-s", TARGET, "244", "245"}, NOT_TARGET, null,
Expect.FAILURE}, // Wrong device connected
new Object[]{new String[]{"244", "245"}, TWO_OTHER_DEVICES, null,
Expect.FAILURE}, // Wrong devices connected
new Object[]{new String[]{"244", "245"}, TARGET_ONLY, null,
Expect.success(244, 245)}, // If only one device connected, guess that one
new Object[]{new String[]{"244", "not_an_atom"}, TARGET_ONLY, null,
Expect.success(244)}, // Ignore non-atoms
new Object[]{new String[]{"not_an_atom"}, TARGET_ONLY, null,
Expect.FAILURE}, // Require at least one atom
new Object[]{new String[]{"244", "245"}, TWO_OTHER_DEVICES, TARGET,
Expect.FAILURE}, // ANDROID_SERIAL specifies non-connected target
new Object[]{new String[]{"244", "245"}, TARGET_AND_OTHER, TARGET,
Expect.success(244, 245)}, // ANDROID_SERIAL specifies a valid target
new Object[]{new String[]{"244", "245"}, TARGET_AND_OTHER, null,
Expect.FAILURE}, // Two connected devices, no indication of which to use
new Object[]{new String[]{"-one", "244", "245"}, TARGET_ONLY, null,
Expect.success(244, 245).onePushedAtomEvent()},
new Object[]{new String[]{"-p", PACKAGE, "244", "245"}, TARGET_ONLY, null,
Expect.success(244, 245).extraPackage()},
new Object[]{new String[]{"-p", PACKAGE, "-one", "244", "245"}, TARGET_ONLY, null,
Expect.success(244, 245).extraPackage().onePushedAtomEvent()},
new Object[]{new String[]{"-one", "-p", PACKAGE, "244", "245"}, TARGET_ONLY, null,
Expect.success(244, 245).extraPackage().onePushedAtomEvent()},
new Object[]{new String[]{"-s", TARGET, "-one", "-p", PACKAGE, "244", "245"},
TARGET_AND_OTHER, null,
Expect.success(244, 245).extraPackage().onePushedAtomEvent()},
new Object[]{new String[]{"-one", "-s", TARGET, "-p", PACKAGE, "244", "245"},
TARGET_AND_OTHER, null,
Expect.success(244, 245).extraPackage().onePushedAtomEvent()},
new Object[]{new String[]{"-one", "-p", PACKAGE, "-s", TARGET, "244", "245"},
TARGET_AND_OTHER, null,
Expect.success(244, 245).extraPackage().onePushedAtomEvent()}
);
}
private final TestDrive.Configuration mConfiguration = new TestDrive.Configuration();
private final TestDrive mTestDrive = new TestDrive();
private static Integer[] collectAtoms(TestDrive.Configuration configuration) {
Integer[] result = new Integer[configuration.mPulledAtoms.size()
+ configuration.mPushedAtoms.size()];
int result_index = 0;
for (Integer atom : configuration.mPushedAtoms) {
result[result_index++] = atom;
}
for (Integer atom : configuration.mPulledAtoms) {
result[result_index++] = atom;
}
Arrays.sort(result);
return result;
}
@Test
public void testProcessArgs() {
boolean result = mTestDrive.processArgs(mConfiguration, mArgs, mConnectedDevices,
mDefaultDevice);
if (mExpect.success) {
assertTrue(result);
assertArrayEquals(mExpect.atoms, collectAtoms(mConfiguration));
assertEquals(mExpect.onePushedAtomEvent, mConfiguration.mOnePushedAtomEvent);
assertEquals(mExpect.target, mTestDrive.mDeviceSerial);
} else {
assertFalse(result);
}
}
}