1/* 2 * Copyright (C) 2012 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 */ 16package android.test; 17 18import android.net.NetworkStats; 19import android.net.TrafficStats; 20import android.os.Bundle; 21import android.util.Log; 22 23import java.lang.reflect.InvocationTargetException; 24import java.lang.reflect.Method; 25import java.lang.reflect.Modifier; 26 27/** 28 * A bandwidth test case that collects bandwidth statistics for tests that are 29 * annotated with {@link BandwidthTest} otherwise the test is executed 30 * as an {@link InstrumentationTestCase} 31 */ 32public class BandwidthTestCase extends InstrumentationTestCase { 33 private static final String TAG = "BandwidthTestCase"; 34 private static final String REPORT_KEY_PACKETS_SENT = "txPackets"; 35 private static final String REPORT_KEY_PACKETS_RECEIVED = "rxPackets"; 36 private static final String REPORT_KEY_BYTES_SENT = "txBytes"; 37 private static final String REPORT_KEY_BYTES_RECEIVED = "rxBytes"; 38 private static final String REPORT_KEY_OPERATIONS = "operations"; 39 40 @Override 41 protected void runTest() throws Throwable { 42 //This is a copy of {@link InstrumentationTestCase#runTest} with 43 //added logic to handle bandwidth measurements 44 String fName = getName(); 45 assertNotNull(fName); 46 Method method = null; 47 Class testClass = null; 48 try { 49 // use getMethod to get all public inherited 50 // methods. getDeclaredMethods returns all 51 // methods of this class but excludes the 52 // inherited ones. 53 testClass = getClass(); 54 method = testClass.getMethod(fName, (Class[]) null); 55 } catch (NoSuchMethodException e) { 56 fail("Method \""+fName+"\" not found"); 57 } 58 59 if (!Modifier.isPublic(method.getModifiers())) { 60 fail("Method \""+fName+"\" should be public"); 61 } 62 63 int runCount = 1; 64 boolean isRepetitive = false; 65 if (method.isAnnotationPresent(FlakyTest.class)) { 66 runCount = method.getAnnotation(FlakyTest.class).tolerance(); 67 } else if (method.isAnnotationPresent(RepetitiveTest.class)) { 68 runCount = method.getAnnotation(RepetitiveTest.class).numIterations(); 69 isRepetitive = true; 70 } 71 72 if (method.isAnnotationPresent(UiThreadTest.class)) { 73 final int tolerance = runCount; 74 final boolean repetitive = isRepetitive; 75 final Method testMethod = method; 76 final Throwable[] exceptions = new Throwable[1]; 77 getInstrumentation().runOnMainSync(new Runnable() { 78 public void run() { 79 try { 80 runMethod(testMethod, tolerance, repetitive); 81 } catch (Throwable throwable) { 82 exceptions[0] = throwable; 83 } 84 } 85 }); 86 if (exceptions[0] != null) { 87 throw exceptions[0]; 88 } 89 } else if (method.isAnnotationPresent(BandwidthTest.class) || 90 testClass.isAnnotationPresent(BandwidthTest.class)) { 91 /** 92 * If bandwidth profiling fails for whatever reason the test 93 * should be allow to execute to its completion. 94 * Typically bandwidth profiling would fail when a lower level 95 * component is missing, such as the kernel module, for a newly 96 * introduced hardware. 97 */ 98 try{ 99 TrafficStats.startDataProfiling(null); 100 } catch(IllegalStateException isx){ 101 Log.w(TAG, "Failed to start bandwidth profiling"); 102 } 103 runMethod(method, 1, false); 104 try{ 105 NetworkStats stats = TrafficStats.stopDataProfiling(null); 106 NetworkStats.Entry entry = stats.getTotal(null); 107 getInstrumentation().sendStatus(2, getBandwidthStats(entry)); 108 } catch (IllegalStateException isx){ 109 Log.w(TAG, "Failed to collect bandwidth stats"); 110 } 111 } else { 112 runMethod(method, runCount, isRepetitive); 113 } 114 } 115 116 private void runMethod(Method runMethod, int tolerance, boolean isRepetitive) throws Throwable { 117 //This is a copy of {@link InstrumentationTestCase#runMethod} 118 Throwable exception = null; 119 120 int runCount = 0; 121 do { 122 try { 123 runMethod.invoke(this, (Object[]) null); 124 exception = null; 125 } catch (InvocationTargetException e) { 126 e.fillInStackTrace(); 127 exception = e.getTargetException(); 128 } catch (IllegalAccessException e) { 129 e.fillInStackTrace(); 130 exception = e; 131 } finally { 132 runCount++; 133 // Report current iteration number, if test is repetitive 134 if (isRepetitive) { 135 Bundle iterations = new Bundle(); 136 iterations.putInt("currentiterations", runCount); 137 getInstrumentation().sendStatus(2, iterations); 138 } 139 } 140 } while ((runCount < tolerance) && (isRepetitive || exception != null)); 141 142 if (exception != null) { 143 throw exception; 144 } 145 } 146 147 private Bundle getBandwidthStats(NetworkStats.Entry entry){ 148 Bundle bundle = new Bundle(); 149 bundle.putLong(REPORT_KEY_BYTES_RECEIVED, entry.rxBytes); 150 bundle.putLong(REPORT_KEY_BYTES_SENT, entry.txBytes); 151 bundle.putLong(REPORT_KEY_PACKETS_RECEIVED, entry.rxPackets); 152 bundle.putLong(REPORT_KEY_PACKETS_SENT, entry.txPackets); 153 bundle.putLong(REPORT_KEY_OPERATIONS, entry.operations); 154 return bundle; 155 } 156} 157 158