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