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 android.multiuser;
17 
18 import static android.multiuser.BenchmarkResults.DECLARED_VALUE_IF_ERROR_MS;
19 
20 import android.app.Activity;
21 import android.app.Instrumentation;
22 import android.os.Bundle;
23 import android.util.Log;
24 
25 import androidx.test.InstrumentationRegistry;
26 
27 import org.junit.rules.TestRule;
28 import org.junit.runner.Description;
29 import org.junit.runners.model.Statement;
30 
31 import java.util.ArrayList;
32 
33 public class BenchmarkResultsReporter implements TestRule {
34     private final BenchmarkRunner mRunner;
35 
BenchmarkResultsReporter(BenchmarkRunner benchmarkRunner)36     public BenchmarkResultsReporter(BenchmarkRunner benchmarkRunner) {
37         mRunner = benchmarkRunner;
38     }
39 
40     @Override
apply(final Statement base, final Description description)41     public Statement apply(final Statement base, final Description description) {
42         return new Statement() {
43             @Override
44             public void evaluate() throws Throwable {
45                 final String tag = description.getTestClass().getSimpleName();
46                 final String methodName = description.getMethodName();
47                 Throwable error = null;
48 
49                 try {
50                     base.evaluate();
51                     error = mRunner.getErrorOrNull();
52                 } catch (Exception e) {
53                     error = e;
54                 }
55 
56                 if (error != null) {
57                     Log.e(tag, "Test " + methodName + " failed.", error);
58                     Log.d(tag, "Logcat displays the results ignoring the fact that it failed;\n"
59                             + "however, fake results of " + DECLARED_VALUE_IF_ERROR_MS + "ms "
60                             + "will be reported to the instrumentation caller to signify failure.");
61                 }
62 
63                 final String summary = getSummaryString(methodName, mRunner.getStatsToLog());
64                 logSummary(tag, summary, mRunner.getAllDurations());
65 
66                 Bundle stats;
67                 if (error == null) {
68                     stats = mRunner.getStatsToReport();
69                     stats.putString(Instrumentation.REPORT_KEY_STREAMRESULT, summary);
70                 } else {
71                     stats = BenchmarkResults.getFailedStatsToReport();
72                     final String failSummary = getSummaryString(methodName,
73                             BenchmarkResults.getFailedStatsToLog());
74                     stats.putString(Instrumentation.REPORT_KEY_STREAMRESULT, failSummary);
75                 }
76                 InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, stats);
77 
78                 if (error != null) {
79                     throw error;
80                 }
81             }
82         };
83     }
84 
85     /**
86      * Prints, for example:
87      *  UserLifecycleTests: (summary string)
88      *  UserLifecycleTests: 1->101
89      *  UserLifecycleTests: 2->102
90      *  UserLifecycleTests: 3->103
91      *  UserLifecycleTests: 4->102
92      */
93     private void logSummary(String tag, String summary, ArrayList<Long> durations) {
94         final StringBuilder sb = new StringBuilder(summary);
95         final int size = durations.size();
96         for (int i = 0; i < size; ++i) {
97             sb.append("\n").append(i+1).append("->").append(durations.get(i));
98         }
99         Log.d(tag, sb.toString());
100     }
101 
102     /**
103      * For example:
104      *  testName
105      *  Sigma (ms): 1
106      *  Mean (ms): 2
107      *  Median (ms): 3
108      */
109     private String getSummaryString(String testName, Bundle stats) {
110         final StringBuilder sb = new StringBuilder();
111         sb.append("\n\n").append(getKey(testName));
112         for (String key : stats.keySet()) {
113             sb.append("\n").append(key).append(": ").append(stats.get(key));
114         }
115         return sb.toString();
116     }
117 
118     private String getKey(String testName) {
119         return testName.replaceAll("Perf$", "");
120     }
121 }
122