blob: dd6bde56a2e41076d8be5272bc71381aa0901740 [file] [log] [blame]
/*
* Copyright (C) 2017 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.tradefed.device.metric;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.times;
import com.android.tradefed.config.OptionSetter;
import com.android.tradefed.invoker.IInvocationContext;
import com.android.tradefed.invoker.InvocationContext;
import com.android.tradefed.metrics.proto.MetricMeasurement.Measurements;
import com.android.tradefed.metrics.proto.MetricMeasurement.Metric;
import com.android.tradefed.result.ByteArrayInputStreamSource;
import com.android.tradefed.result.ITestInvocationListener;
import com.android.tradefed.result.LogDataType;
import com.android.tradefed.result.TestDescription;
import com.android.tradefed.testtype.HostTest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** Unit tests for {@link BaseDeviceMetricCollector}. */
@RunWith(JUnit4.class)
public class BaseDeviceMetricCollectorTest {
private BaseDeviceMetricCollector mBase;
private IInvocationContext mContext;
private ITestInvocationListener mMockListener;
@Captor private ArgumentCaptor<HashMap<String, Metric>> mCapturedMetrics;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mBase = new BaseDeviceMetricCollector();
mContext = new InvocationContext();
mMockListener = Mockito.mock(ITestInvocationListener.class);
}
@Test
public void testInitAndForwarding() {
mBase.init(mContext, mMockListener);
mBase.invocationStarted(mContext);
mBase.testRunStarted("testRun", 1);
TestDescription test = new TestDescription("class", "method");
mBase.testStarted(test);
mBase.testLog("dataname", LogDataType.TEXT, new ByteArrayInputStreamSource("".getBytes()));
mBase.testFailed(test, "trace");
mBase.testAssumptionFailure(test, "trace");
mBase.testIgnored(test);
mBase.testEnded(test, new HashMap<String, Metric>());
mBase.testRunFailed("test run failed");
mBase.testRunStopped(0L);
mBase.testRunEnded(0L, new HashMap<String, Metric>());
mBase.invocationFailed(new Throwable());
mBase.invocationEnded(0L);
Mockito.verify(mMockListener, times(1)).invocationStarted(Mockito.any());
Mockito.verify(mMockListener, times(1)).testRunStarted("testRun", 1);
Mockito.verify(mMockListener, times(1)).testStarted(Mockito.eq(test), Mockito.anyLong());
Mockito.verify(mMockListener, times(1))
.testLog(Mockito.eq("dataname"), Mockito.eq(LogDataType.TEXT), Mockito.any());
Mockito.verify(mMockListener, times(1)).testFailed(test, "trace");
Mockito.verify(mMockListener, times(1)).testAssumptionFailure(test, "trace");
Mockito.verify(mMockListener, times(1)).testIgnored(test);
Mockito.verify(mMockListener, times(1))
.testEnded(
Mockito.eq(test),
Mockito.anyLong(),
Mockito.eq(new HashMap<String, Metric>()));
Mockito.verify(mMockListener, times(1)).testRunFailed("test run failed");
Mockito.verify(mMockListener, times(1)).testRunStopped(0L);
Mockito.verify(mMockListener, times(1)).testRunEnded(0L, new HashMap<String, Metric>());
Mockito.verify(mMockListener, times(1)).invocationFailed(Mockito.any());
Mockito.verify(mMockListener, times(1)).invocationEnded(0L);
Assert.assertSame(mMockListener, mBase.getInvocationListener());
Assert.assertEquals(0, mBase.getDevices().size());
Assert.assertEquals(0, mBase.getBuildInfos().size());
}
/**
* Test to ensure that the forwarding of events continues even if an exception occurs in the
* collection.
*/
@Test
public void testForwarding_withException() {
mBase =
new BaseDeviceMetricCollector() {
@Override
public void onTestRunStart(DeviceMetricData runData) {
throw new RuntimeException("Failed onTestRunStart.");
}
@Override
public void onTestRunEnd(
DeviceMetricData runData, final Map<String, Metric> currentRunMetrics) {
throw new RuntimeException("Failed onTestRunEnd");
}
@Override
public void onTestStart(DeviceMetricData testData) {
throw new RuntimeException("Failed onTestStart");
}
@Override
public void onTestEnd(
DeviceMetricData testData,
final Map<String, Metric> currentTestCaseMetrics) {
throw new RuntimeException("Failed onTestEnd");
}
};
mBase.init(mContext, mMockListener);
mBase.invocationStarted(mContext);
mBase.testRunStarted("testRun", 1);
TestDescription test = new TestDescription("class", "method");
mBase.testStarted(test);
mBase.testLog("dataname", LogDataType.TEXT, new ByteArrayInputStreamSource("".getBytes()));
mBase.testFailed(test, "trace");
mBase.testAssumptionFailure(test, "trace");
mBase.testIgnored(test);
mBase.testEnded(test, new HashMap<String, Metric>());
mBase.testRunFailed("test run failed");
mBase.testRunStopped(0L);
mBase.testRunEnded(0L, new HashMap<String, Metric>());
mBase.invocationFailed(new Throwable());
mBase.invocationEnded(0L);
Mockito.verify(mMockListener, times(1)).invocationStarted(Mockito.any());
Mockito.verify(mMockListener, times(1)).testRunStarted("testRun", 1);
Mockito.verify(mMockListener, times(1)).testStarted(Mockito.eq(test), Mockito.anyLong());
Mockito.verify(mMockListener, times(1))
.testLog(Mockito.eq("dataname"), Mockito.eq(LogDataType.TEXT), Mockito.any());
Mockito.verify(mMockListener, times(1)).testFailed(test, "trace");
Mockito.verify(mMockListener, times(1)).testAssumptionFailure(test, "trace");
Mockito.verify(mMockListener, times(1)).testIgnored(test);
Mockito.verify(mMockListener, times(1))
.testEnded(
Mockito.eq(test),
Mockito.anyLong(),
Mockito.eq(new HashMap<String, Metric>()));
Mockito.verify(mMockListener, times(1)).testRunFailed("test run failed");
Mockito.verify(mMockListener, times(1)).testRunStopped(0L);
Mockito.verify(mMockListener, times(1)).testRunEnded(0L, new HashMap<String, Metric>());
Mockito.verify(mMockListener, times(1)).invocationFailed(Mockito.any());
Mockito.verify(mMockListener, times(1)).invocationEnded(0L);
Assert.assertSame(mMockListener, mBase.getInvocationListener());
Assert.assertEquals(0, mBase.getDevices().size());
Assert.assertEquals(0, mBase.getBuildInfos().size());
}
/**
* Test that if we specify an include group and the test case does not have any group, we do not
* run the collector against it.
*/
@Test
public void testIncludeTestCase_optionGroup_noAnnotation() throws Exception {
mBase = new TwoMetricsBaseCollector();
OptionSetter setter = new OptionSetter(mBase);
setter.setOptionValue(BaseDeviceMetricCollector.TEST_CASE_INCLUDE_GROUP_OPTION, "group");
verifyFiltering(mBase, null, false);
}
/**
* Test that if we specify an include group and the test case does not match it, we do not run
* the collector against it.
*/
@Test
public void testIncludeTestCase_optionGroup_differentAnnotationGroup() throws Exception {
mBase = new TwoMetricsBaseCollector();
OptionSetter setter = new OptionSetter(mBase);
setter.setOptionValue(BaseDeviceMetricCollector.TEST_CASE_INCLUDE_GROUP_OPTION, "group");
verifyFiltering(mBase, new TestAnnotation("group1"), false);
}
/**
* Test that if we specify an include group and the test case match it, we run the collector
* against it.
*/
@Test
public void testIncludeTestCase_optionGroup_sameAnnotationGroup() throws Exception {
mBase = new TwoMetricsBaseCollector();
OptionSetter setter = new OptionSetter(mBase);
setter.setOptionValue(BaseDeviceMetricCollector.TEST_CASE_INCLUDE_GROUP_OPTION, "group");
verifyFiltering(mBase, new TestAnnotation("group"), true);
}
/**
* Test that if we specify an include group and one of the test case group match it, we run the
* collector against it.
*/
@Test
public void testIncludeTestCase_optionGroup_multiGroup() throws Exception {
mBase = new TwoMetricsBaseCollector();
OptionSetter setter = new OptionSetter(mBase);
setter.setOptionValue(BaseDeviceMetricCollector.TEST_CASE_INCLUDE_GROUP_OPTION, "group");
verifyFiltering(mBase, new TestAnnotation("group1,group2,group"), true);
}
/**
* Test that if we do not specify an include group and the test case have some, we run the
* collector against it since there is no filtering.
*/
@Test
public void testIncludeTestCase_noOptionGroup_multiGroup() throws Exception {
mBase = new TwoMetricsBaseCollector();
verifyFiltering(mBase, new TestAnnotation("group1,group2,group"), true);
}
/**
* Test that if we exclude a group and the test case does not belong to any, we run the
* collection against it.
*/
@Test
public void testExcludeTestCase_optionGroup_noAnnotation() throws Exception {
mBase = new TwoMetricsBaseCollector();
OptionSetter setter = new OptionSetter(mBase);
setter.setOptionValue(BaseDeviceMetricCollector.TEST_CASE_EXCLUDE_GROUP_OPTION, "group");
verifyFiltering(mBase, null, true);
}
/**
* Test that if we exclude a group and the test case belong to it, we do not run the collection
* against it.
*/
@Test
public void testExcludeTestCase_optionGroup_sameGroup() throws Exception {
mBase = new TwoMetricsBaseCollector();
OptionSetter setter = new OptionSetter(mBase);
setter.setOptionValue(BaseDeviceMetricCollector.TEST_CASE_EXCLUDE_GROUP_OPTION, "group");
verifyFiltering(mBase, new TestAnnotation("group"), false);
}
/**
* Test that if we exclude a group and the test case belong to it, we do not run the collection
* against it.
*/
@Test
public void testExcludeTestCase_optionGroup_multiGroup() throws Exception {
mBase = new TwoMetricsBaseCollector();
OptionSetter setter = new OptionSetter(mBase);
setter.setOptionValue(BaseDeviceMetricCollector.TEST_CASE_EXCLUDE_GROUP_OPTION, "group");
verifyFiltering(mBase, new TestAnnotation("group1,group2,group"), false);
}
/** Test that if we exclude and include a group. It will be excluded. */
@Test
public void testExcludeTestCase_includeAndExclude() throws Exception {
mBase = new TwoMetricsBaseCollector();
OptionSetter setter = new OptionSetter(mBase);
setter.setOptionValue(BaseDeviceMetricCollector.TEST_CASE_EXCLUDE_GROUP_OPTION, "group");
setter.setOptionValue(BaseDeviceMetricCollector.TEST_CASE_INCLUDE_GROUP_OPTION, "group");
verifyFiltering(mBase, new TestAnnotation("group1,group2,group"), false);
}
/**
* Validate that the filtering allows or not the collection of metrics based on the annotation
* of the test case.
*/
private void verifyFiltering(
BaseDeviceMetricCollector base, TestAnnotation annot, boolean hasMetric) {
base.init(mContext, mMockListener);
base.invocationStarted(mContext);
base.testRunStarted("testRun", 1);
TestDescription test = null;
if (annot != null) {
test = new TestDescription("class", "method", annot);
} else {
test = new TestDescription("class", "method");
}
base.testStarted(test);
base.testEnded(test, new HashMap<String, Metric>());
base.testRunEnded(0L, new HashMap<String, Metric>());
base.invocationEnded(0L);
Mockito.verify(mMockListener, times(1)).invocationStarted(Mockito.any());
Mockito.verify(mMockListener, times(1)).testRunStarted("testRun", 1);
Mockito.verify(mMockListener, times(1)).testStarted(Mockito.eq(test), Mockito.anyLong());
// Metrics should have been skipped, so the map should be empty.
Mockito.verify(mMockListener, times(1))
.testEnded(Mockito.eq(test), Mockito.anyLong(), mCapturedMetrics.capture());
Mockito.verify(mMockListener, times(1)).testRunEnded(0L, new HashMap<String, Metric>());
Mockito.verify(mMockListener, times(1)).invocationEnded(0L);
Assert.assertSame(mMockListener, mBase.getInvocationListener());
Assert.assertEquals(0, mBase.getDevices().size());
Assert.assertEquals(0, mBase.getBuildInfos().size());
if (hasMetric) {
// One metric for testStart and one for testEnd
Assert.assertEquals(2, mCapturedMetrics.getValue().size());
} else {
Assert.assertEquals(0, mCapturedMetrics.getValue().size());
}
}
/** Test annotation to test filtering of test cases. */
public class TestAnnotation implements MetricOption {
private String mGroup;
public TestAnnotation(String group) {
mGroup = group;
}
@Override
public Class<? extends Annotation> annotationType() {
return MetricOption.class;
}
@Override
public String group() {
return mGroup;
}
}
/** Test class for testing filtering of metrics. */
public class TwoMetricsBaseCollector extends BaseDeviceMetricCollector {
@Override
public void onTestStart(DeviceMetricData testData) {
testData.addMetric(
"onteststart",
Metric.newBuilder()
.setMeasurements(Measurements.newBuilder().setSingleString("value1")));
}
@Override
public void onTestEnd(
DeviceMetricData testData, final Map<String, Metric> currentTestCaseMetrics) {
testData.addMetric(
"ontestend",
Metric.newBuilder()
.setMeasurements(Measurements.newBuilder().setSingleString("value1")));
}
}
/** Test class actually annotated with groups. */
@RunWith(JUnit4.class)
public static class TestRunAnnotated {
@MetricOption(group = "group1")
@Test
public void testOne() {}
@MetricOption(group = "group1,group2")
@Test
public void testTwo() {}
@MetricOption(group = "group2")
@Test
public void testThree() {}
}
/**
* Test when actually running an annotated class that the proper groups only are collected even
* if the test ran.
*/
@Test
public void testActualRunAnnotated_include() throws Exception {
mBase = new TwoMetricsBaseCollector();
OptionSetter setter = new OptionSetter(mBase);
setter.setOptionValue(BaseDeviceMetricCollector.TEST_CASE_INCLUDE_GROUP_OPTION, "group1");
mBase.init(mContext, mMockListener);
mBase.invocationStarted(mContext);
HostTest host = new HostTest();
OptionSetter setterHost = new OptionSetter(host);
setterHost.setOptionValue("class", TestRunAnnotated.class.getName());
setterHost.setOptionValue("enable-pretty-logs", "false");
host.run(mBase);
Mockito.verify(mMockListener, times(1)).testRunStarted(TestRunAnnotated.class.getName(), 3);
TestDescription test1 = new TestDescription(TestRunAnnotated.class.getName(), "testOne");
TestDescription test2 = new TestDescription(TestRunAnnotated.class.getName(), "testTwo");
TestDescription test3 = new TestDescription(TestRunAnnotated.class.getName(), "testThree");
Mockito.verify(mMockListener, times(1)).testStarted(Mockito.eq(test1), Mockito.anyLong());
Mockito.verify(mMockListener, times(1))
.testEnded(Mockito.eq(test1), Mockito.anyLong(), mCapturedMetrics.capture());
Mockito.verify(mMockListener, times(1)).testStarted(Mockito.eq(test2), Mockito.anyLong());
Mockito.verify(mMockListener, times(1))
.testEnded(Mockito.eq(test2), Mockito.anyLong(), mCapturedMetrics.capture());
Mockito.verify(mMockListener, times(1)).testStarted(Mockito.eq(test3), Mockito.anyLong());
// Metrics should have been skipped, so the map should be empty.
Mockito.verify(mMockListener, times(1))
.testEnded(Mockito.eq(test3), Mockito.anyLong(), mCapturedMetrics.capture());
Mockito.verify(mMockListener, times(1))
.testRunEnded(Mockito.anyLong(), (HashMap<String, Metric>) Mockito.any());
List<HashMap<String, Metric>> allValues = mCapturedMetrics.getAllValues();
// For test1
assertTrue(allValues.get(0).containsKey("onteststart"));
assertTrue(allValues.get(0).containsKey("ontestend"));
// For test2
assertTrue(allValues.get(1).containsKey("onteststart"));
assertTrue(allValues.get(1).containsKey("ontestend"));
// For test3: should not have any metrics.
assertFalse(allValues.get(2).containsKey("onteststart"));
assertFalse(allValues.get(2).containsKey("ontestend"));
}
/** Test running an actual test annotated for metrics for an exclusion scenario. */
@Test
public void testActualRunAnnotated_exclude() throws Exception {
mBase = new TwoMetricsBaseCollector();
OptionSetter setter = new OptionSetter(mBase);
setter.setOptionValue(BaseDeviceMetricCollector.TEST_CASE_EXCLUDE_GROUP_OPTION, "group1");
mBase.init(mContext, mMockListener);
mBase.invocationStarted(mContext);
HostTest host = new HostTest();
OptionSetter setterHost = new OptionSetter(host);
setterHost.setOptionValue("class", TestRunAnnotated.class.getName());
setterHost.setOptionValue("enable-pretty-logs", "false");
host.run(mBase);
Mockito.verify(mMockListener, times(1)).testRunStarted(TestRunAnnotated.class.getName(), 3);
TestDescription test1 = new TestDescription(TestRunAnnotated.class.getName(), "testOne");
TestDescription test2 = new TestDescription(TestRunAnnotated.class.getName(), "testTwo");
TestDescription test3 = new TestDescription(TestRunAnnotated.class.getName(), "testThree");
Mockito.verify(mMockListener, times(1)).testStarted(Mockito.eq(test1), Mockito.anyLong());
Mockito.verify(mMockListener, times(1))
.testEnded(Mockito.eq(test1), Mockito.anyLong(), mCapturedMetrics.capture());
Mockito.verify(mMockListener, times(1)).testStarted(Mockito.eq(test2), Mockito.anyLong());
Mockito.verify(mMockListener, times(1))
.testEnded(Mockito.eq(test2), Mockito.anyLong(), mCapturedMetrics.capture());
Mockito.verify(mMockListener, times(1)).testStarted(Mockito.eq(test3), Mockito.anyLong());
// Metrics should have been skipped, so the map should be empty.
Mockito.verify(mMockListener, times(1))
.testEnded(Mockito.eq(test3), Mockito.anyLong(), mCapturedMetrics.capture());
Mockito.verify(mMockListener, times(1))
.testRunEnded(Mockito.anyLong(), (HashMap<String, Metric>) Mockito.any());
List<HashMap<String, Metric>> allValues = mCapturedMetrics.getAllValues();
// For test1
assertFalse(allValues.get(0).containsKey("onteststart"));
assertFalse(allValues.get(0).containsKey("ontestend"));
// For test2
assertFalse(allValues.get(1).containsKey("onteststart"));
assertFalse(allValues.get(1).containsKey("ontestend"));
// For test3: Should be the only WITH metrics since the other two were excluded.
assertTrue(allValues.get(2).containsKey("onteststart"));
assertTrue(allValues.get(2).containsKey("ontestend"));
}
}