| /* |
| * Copyright (C) 2012 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.test; |
| |
| import android.net.NetworkStats; |
| import android.net.TrafficStats; |
| import android.os.Bundle; |
| import android.util.Log; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| |
| /** |
| * A bandwidth test case that collects bandwidth statistics for tests that are |
| * annotated with {@link BandwidthTest} otherwise the test is executed |
| * as an {@link InstrumentationTestCase} |
| */ |
| public class BandwidthTestCase extends InstrumentationTestCase { |
| private static final String TAG = "BandwidthTestCase"; |
| private static final String REPORT_KEY_PACKETS_SENT = "txPackets"; |
| private static final String REPORT_KEY_PACKETS_RECEIVED = "rxPackets"; |
| private static final String REPORT_KEY_BYTES_SENT = "txBytes"; |
| private static final String REPORT_KEY_BYTES_RECEIVED = "rxBytes"; |
| private static final String REPORT_KEY_OPERATIONS = "operations"; |
| |
| @Override |
| protected void runTest() throws Throwable { |
| //This is a copy of {@link InstrumentationTestCase#runTest} with |
| //added logic to handle bandwidth measurements |
| String fName = getName(); |
| assertNotNull(fName); |
| Method method = null; |
| Class testClass = null; |
| try { |
| // use getMethod to get all public inherited |
| // methods. getDeclaredMethods returns all |
| // methods of this class but excludes the |
| // inherited ones. |
| testClass = getClass(); |
| method = testClass.getMethod(fName, (Class[]) null); |
| } catch (NoSuchMethodException e) { |
| fail("Method \""+fName+"\" not found"); |
| } |
| |
| if (!Modifier.isPublic(method.getModifiers())) { |
| fail("Method \""+fName+"\" should be public"); |
| } |
| |
| int runCount = 1; |
| boolean isRepetitive = false; |
| if (method.isAnnotationPresent(FlakyTest.class)) { |
| runCount = method.getAnnotation(FlakyTest.class).tolerance(); |
| } else if (method.isAnnotationPresent(RepetitiveTest.class)) { |
| runCount = method.getAnnotation(RepetitiveTest.class).numIterations(); |
| isRepetitive = true; |
| } |
| |
| if (method.isAnnotationPresent(UiThreadTest.class)) { |
| final int tolerance = runCount; |
| final boolean repetitive = isRepetitive; |
| final Method testMethod = method; |
| final Throwable[] exceptions = new Throwable[1]; |
| getInstrumentation().runOnMainSync(new Runnable() { |
| public void run() { |
| try { |
| runMethod(testMethod, tolerance, repetitive); |
| } catch (Throwable throwable) { |
| exceptions[0] = throwable; |
| } |
| } |
| }); |
| if (exceptions[0] != null) { |
| throw exceptions[0]; |
| } |
| } else if (method.isAnnotationPresent(BandwidthTest.class) || |
| testClass.isAnnotationPresent(BandwidthTest.class)) { |
| /** |
| * If bandwidth profiling fails for whatever reason the test |
| * should be allow to execute to its completion. |
| * Typically bandwidth profiling would fail when a lower level |
| * component is missing, such as the kernel module, for a newly |
| * introduced hardware. |
| */ |
| try{ |
| TrafficStats.startDataProfiling(null); |
| } catch(IllegalStateException isx){ |
| Log.w(TAG, "Failed to start bandwidth profiling"); |
| } |
| runMethod(method, 1, false); |
| try{ |
| NetworkStats stats = TrafficStats.stopDataProfiling(null); |
| NetworkStats.Entry entry = stats.getTotal(null); |
| getInstrumentation().sendStatus(2, getBandwidthStats(entry)); |
| } catch (IllegalStateException isx){ |
| Log.w(TAG, "Failed to collect bandwidth stats"); |
| } |
| } else { |
| runMethod(method, runCount, isRepetitive); |
| } |
| } |
| |
| private void runMethod(Method runMethod, int tolerance, boolean isRepetitive) throws Throwable { |
| //This is a copy of {@link InstrumentationTestCase#runMethod} |
| Throwable exception = null; |
| |
| int runCount = 0; |
| do { |
| try { |
| runMethod.invoke(this, (Object[]) null); |
| exception = null; |
| } catch (InvocationTargetException e) { |
| e.fillInStackTrace(); |
| exception = e.getTargetException(); |
| } catch (IllegalAccessException e) { |
| e.fillInStackTrace(); |
| exception = e; |
| } finally { |
| runCount++; |
| // Report current iteration number, if test is repetitive |
| if (isRepetitive) { |
| Bundle iterations = new Bundle(); |
| iterations.putInt("currentiterations", runCount); |
| getInstrumentation().sendStatus(2, iterations); |
| } |
| } |
| } while ((runCount < tolerance) && (isRepetitive || exception != null)); |
| |
| if (exception != null) { |
| throw exception; |
| } |
| } |
| |
| private Bundle getBandwidthStats(NetworkStats.Entry entry){ |
| Bundle bundle = new Bundle(); |
| bundle.putLong(REPORT_KEY_BYTES_RECEIVED, entry.rxBytes); |
| bundle.putLong(REPORT_KEY_BYTES_SENT, entry.txBytes); |
| bundle.putLong(REPORT_KEY_PACKETS_RECEIVED, entry.rxPackets); |
| bundle.putLong(REPORT_KEY_PACKETS_SENT, entry.txPackets); |
| bundle.putLong(REPORT_KEY_OPERATIONS, entry.operations); |
| return bundle; |
| } |
| } |
| |