1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.tradefed.device.metric; 17 18 import static org.junit.Assert.assertEquals; 19 import static org.junit.Assert.assertTrue; 20 import static org.junit.Assert.fail; 21 22 import com.android.tradefed.config.OptionSetter; 23 import com.android.tradefed.device.ITestDevice; 24 import com.android.tradefed.invoker.IInvocationContext; 25 import com.android.tradefed.invoker.InvocationContext; 26 import com.android.tradefed.metrics.proto.MetricMeasurement.Measurements; 27 import com.android.tradefed.metrics.proto.MetricMeasurement.Metric; 28 import com.android.tradefed.result.ITestInvocationListener; 29 import com.android.tradefed.util.RunUtil; 30 31 import org.junit.Before; 32 import org.junit.Rule; 33 import org.junit.Test; 34 import org.junit.rules.TemporaryFolder; 35 import org.junit.runner.RunWith; 36 import org.junit.runners.JUnit4; 37 import org.mockito.Mock; 38 import org.mockito.MockitoAnnotations; 39 import org.mockito.Spy; 40 41 import java.io.File; 42 import java.util.ArrayList; 43 import java.util.HashMap; 44 import java.util.List; 45 import java.util.Map; 46 47 /** Unit tests for {@link ScheduleMultipleDeviceMetricCollector}. */ 48 @RunWith(JUnit4.class) 49 public class ScheduleMultipleDeviceMetricCollectorTest { 50 @Rule public final TemporaryFolder folder = new TemporaryFolder(); 51 @Mock private ITestDevice mTestDevice; 52 @Mock private ITestInvocationListener mMockListener; 53 @Spy private ScheduleMultipleDeviceMetricCollector mMultipleMetricCollector; 54 55 private IInvocationContext mContext; 56 57 static class TestMeminfoCollector extends ScheduledDeviceMetricCollector { 58 private int mInternalCounter = 0; 59 private String key = "meminfo"; 60 61 TestMeminfoCollector() { 62 setTag("meminfoInterval"); 63 } 64 65 @Override 66 public void collect(ITestDevice device, DeviceMetricData runData) 67 throws InterruptedException { 68 mInternalCounter++; 69 runData.addMetricForDevice( 70 device, 71 key + mInternalCounter, 72 Metric.newBuilder() 73 .setMeasurements( 74 Measurements.newBuilder() 75 .setSingleString("value" + mInternalCounter))); 76 } 77 } 78 79 static class TestJankinfoCollector extends ScheduledDeviceMetricCollector { 80 private int mInternalCounter = 0; 81 private String key = "jankinfo"; 82 83 TestJankinfoCollector() { 84 setTag("jankInterval"); 85 } 86 87 @Override 88 public void collect(ITestDevice device, DeviceMetricData runData) 89 throws InterruptedException { 90 mInternalCounter++; 91 runData.addMetricForDevice( 92 device, 93 key + mInternalCounter, 94 Metric.newBuilder() 95 .setMeasurements( 96 Measurements.newBuilder() 97 .setSingleString("value" + mInternalCounter))); 98 } 99 } 100 101 static class TestFragmentationCollector extends ScheduledDeviceMetricCollector { 102 private int mInternalCounter = 0; 103 private String key = "fragmentation"; 104 105 TestFragmentationCollector() { 106 setTag("fragmentationInterval"); 107 } 108 109 @Override 110 public void collect(ITestDevice device, DeviceMetricData runData) 111 throws InterruptedException { 112 mInternalCounter++; 113 runData.addMetricForDevice( 114 device, 115 key + mInternalCounter, 116 Metric.newBuilder() 117 .setMeasurements( 118 Measurements.newBuilder() 119 .setSingleString("value" + mInternalCounter))); 120 } 121 } 122 123 @Before 124 public void setUp() throws Exception { 125 MockitoAnnotations.initMocks(this); 126 mContext = new InvocationContext(); 127 mContext.addAllocatedDevice("test device", mTestDevice); 128 } 129 130 @Test 131 public void testMultipleMetricCollector_success() throws Exception { 132 OptionSetter setter = new OptionSetter(mMultipleMetricCollector); 133 134 // Set up the metric collection storage path. 135 File metricStoragePath = folder.newFolder(); 136 setter.setOptionValue("metric-storage-path", metricStoragePath.toString()); 137 138 // Set up the intervals. 139 Map<String, Long> intervals = new HashMap<>(); 140 intervals.put("meminfoInterval", 100L); 141 intervals.put("fragmentationInterval", 100L); 142 intervals.put("jankInterval", 100L); 143 for (String key : intervals.keySet()) { 144 setter.setOptionValue( 145 "metric-collection-intervals", key, intervals.get(key).toString()); 146 } 147 148 // Request the collectors. 149 List<String> classnames = new ArrayList<>(); 150 classnames.add(TestMeminfoCollector.class.getName()); 151 classnames.add(TestJankinfoCollector.class.getName()); 152 classnames.add(TestFragmentationCollector.class.getName()); 153 for (String key : classnames) { 154 setter.setOptionValue("metric-collector-command-classes", key); 155 } 156 157 DeviceMetricData runData = new DeviceMetricData(mContext); 158 159 // Start the tests. 160 HashMap<String, Metric> metrics = new HashMap<>(); 161 mMultipleMetricCollector.init(mContext, mMockListener); 162 try { 163 mMultipleMetricCollector.onTestRunStart(runData); 164 RunUtil.getDefault().sleep(500); 165 } finally { 166 mMultipleMetricCollector.onTestRunEnd(runData, metrics); 167 } 168 169 // We give it 500msec to run and 100msec interval we should easily have at least run all the 170 // metrics once. 171 // assert that the metrics contains filenames of all the collected metrics. 172 HashMap<String, Metric> metricsCollected = new HashMap<>(); 173 runData.addToMetrics(metricsCollected); 174 175 assertTrue(metricsCollected.containsKey("jankinfo1")); 176 assertTrue(metricsCollected.containsKey("meminfo1")); 177 assertTrue(metricsCollected.containsKey("fragmentation1")); 178 } 179 180 @Test 181 public void testMultipleMetricCollector_noFailureEvenIfNoCollectorRequested() throws Exception { 182 HashMap<String, Metric> metrics = new HashMap<>(); 183 mMultipleMetricCollector.init(mContext, mMockListener); 184 185 DeviceMetricData runData = new DeviceMetricData(mContext); 186 187 try { 188 mMultipleMetricCollector.onTestRunStart(runData); 189 RunUtil.getDefault().sleep(500); 190 } finally { 191 mMultipleMetricCollector.onTestRunEnd(runData, metrics); 192 } 193 194 // No metrics should have been collected. 195 HashMap<String, Metric> metricsCollected = new HashMap<>(); 196 runData.addToMetrics(metricsCollected); 197 198 assertEquals(0, metricsCollected.size()); 199 } 200 201 /** Test that if a specified collector does not exists, we ignore it and proceed. */ 202 @Test 203 public void testMultipleMetricCollector_collectorNotFound() throws Exception { 204 OptionSetter setter = new OptionSetter(mMultipleMetricCollector); 205 206 // Set up the metric collection storage path. 207 File metricStoragePath = folder.newFolder(); 208 setter.setOptionValue("metric-storage-path", metricStoragePath.toString()); 209 210 // Set up the intervals. 211 Map<String, Long> intervals = new HashMap<>(); 212 intervals.put("meminfoInterval", 100L); 213 for (String key : intervals.keySet()) { 214 setter.setOptionValue( 215 "metric-collection-intervals", key, intervals.get(key).toString()); 216 } 217 218 // Request the collectors. 219 List<String> classnames = new ArrayList<>(); 220 classnames.add(TestMeminfoCollector.class.getName()); 221 classnames.add("this.does.not.exists.collector"); 222 for (String key : classnames) { 223 setter.setOptionValue("metric-collector-command-classes", key); 224 } 225 226 HashMap<String, Metric> metrics = new HashMap<>(); 227 mMultipleMetricCollector.init(mContext, mMockListener); 228 229 DeviceMetricData runData = new DeviceMetricData(mContext); 230 231 try { 232 mMultipleMetricCollector.onTestRunStart(runData); 233 RunUtil.getDefault().sleep(500); 234 } finally { 235 mMultipleMetricCollector.onTestRunEnd(runData, metrics); 236 } 237 238 // No metrics should have been collected. 239 HashMap<String, Metric> metricsCollected = new HashMap<>(); 240 runData.addToMetrics(metricsCollected); 241 242 assertTrue(metricsCollected.containsKey("meminfo1")); 243 } 244 245 @Test 246 public void testMultipleMetricCollector_failsForNonNegativeInterval() throws Exception { 247 String expectedStderr = 248 "class com.android.tradefed.device.metric." 249 + "ScheduleMultipleDeviceMetricCollectorTest$TestJankinfoCollector expects " 250 + "a non negative interval."; 251 252 OptionSetter setter = new OptionSetter(mMultipleMetricCollector); 253 254 // Set up the metric collection storage path. 255 setter.setOptionValue("metric-storage-path", folder.newFolder().toString()); 256 257 // Set up the interval. 258 Map<String, Long> intervals = new HashMap<>(); 259 intervals.put("jankInterval", -100L); 260 for (String key : intervals.keySet()) { 261 setter.setOptionValue( 262 "metric-collection-intervals", key, intervals.get(key).toString()); 263 } 264 265 // Set up the classname. 266 List<String> classnames = new ArrayList<>(); 267 classnames.add(TestJankinfoCollector.class.getName()); 268 for (String key : classnames) { 269 setter.setOptionValue("metric-collector-command-classes", key); 270 } 271 272 DeviceMetricData runData = new DeviceMetricData(mContext); 273 274 // Start the tests, which should fail with the expected error message. 275 mMultipleMetricCollector.init(mContext, mMockListener); 276 277 try { 278 mMultipleMetricCollector.onTestRunStart(runData); 279 fail("Should throw illegal argument exception in case of negative intervals."); 280 } catch (IllegalArgumentException e) { 281 assertEquals(expectedStderr, e.getMessage()); 282 } 283 } 284 } 285