Skip to content

Commit d1f9226

Browse files
brettchabotcopybara-androidxtest
authored andcommitted
Trim and truncate test failure stack traces for both orchestrator and classic/non-orchestrator modes.
This change should clean up test failure reporting by: - Remove test runner framework related stack frames - Truncate stack traces to a 64KB size when running under orchestrator to attempt to avoid binder transaction limits. This limit is already enforced when running in classic/non-orchestrator mode JUnit 4.13 has a really nice getTrimmedStackTrace feature, but androidx.test is fixed to 4.12 for the time being. So as a temporary workaround, copy the relevant JUnit change junit-team/junit4#1028 into this project. Fixes #729, and hopefully #269 PiperOrigin-RevId: 329797783
1 parent 4bd7957 commit d1f9226

File tree

10 files changed

+364
-49
lines changed

10 files changed

+364
-49
lines changed

runner/android_junit_runner/java/androidx/test/internal/runner/listener/InstrumentationResultPrinter.java

+3-13
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import android.os.Bundle;
2020
import androidx.annotation.VisibleForTesting;
2121
import android.util.Log;
22+
import androidx.test.services.events.internal.StackTrimmer;
2223
import java.io.PrintStream;
2324
import org.junit.internal.TextListener;
2425
import org.junit.runner.Description;
@@ -45,8 +46,6 @@ public class InstrumentationResultPrinter extends InstrumentationRunListener {
4546

4647
private static final String TAG = "InstrumentationResultPrinter";
4748

48-
@VisibleForTesting static final int MAX_TRACE_SIZE = 64 * 1024;
49-
5049
/**
5150
* This value, if stored with key {@link android.app.Instrumentation#REPORT_KEY_IDENTIFIER},
5251
* identifies AndroidJUnitRunner as the source of the report. This is sent with all status
@@ -175,21 +174,12 @@ public void testAssumptionFailure(Failure failure) {
175174
}
176175

177176
private void reportFailure(Failure failure) {
178-
String trace = failure.getTrace();
179-
if (trace.length() > MAX_TRACE_SIZE) {
180-
// Since AJUR needs to report failures back to AM via a binder IPC, we need to make sure that
181-
// we don't exceed the Binder transaction limit - which is 1MB per process.
182-
Log.w(
183-
TAG,
184-
String.format("Stack trace too long, trimmed to first %s characters.", MAX_TRACE_SIZE));
185-
trace = trace.substring(0, MAX_TRACE_SIZE) + "\n";
186-
}
177+
String trace = StackTrimmer.getTrimmedStackTrace(failure);
187178
testResult.putString(REPORT_KEY_STACK, trace);
188179
// pretty printing
189180
testResult.putString(
190181
Instrumentation.REPORT_KEY_STREAMRESULT,
191-
String.format(
192-
"\nError in %s:\n%s", failure.getDescription().getDisplayName(), failure.getTrace()));
182+
String.format("\nError in %s:\n%s", failure.getDescription().getDisplayName(), trace));
193183
}
194184

195185
@Override

runner/android_junit_runner/java/androidx/test/orchestrator/junit/ParcelableFailure.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@
1919
import android.os.Parcel;
2020
import android.os.Parcelable;
2121
import android.util.Log;
22+
import androidx.test.services.events.internal.StackTrimmer;
2223
import org.junit.runner.notification.Failure;
2324

24-
/** Parcelable imitation of a JUnit ParcelableFailure */
25+
/** Parcelable imitation of a JUnit Failure */
2526
public final class ParcelableFailure implements Parcelable {
2627

2728
private static final String TAG = "ParcelableFailure";
@@ -33,7 +34,7 @@ public final class ParcelableFailure implements Parcelable {
3334

3435
public ParcelableFailure(Failure failure) {
3536
this.description = new ParcelableDescription(failure.getDescription());
36-
this.trace = failure.getTrace();
37+
this.trace = StackTrimmer.getTrimmedStackTrace(failure);
3738
}
3839

3940
private ParcelableFailure(Parcel in) {

runner/android_junit_runner/javatests/androidx/test/internal/events/client/OrchestratedInstrumentationListenerTest.java

+8-8
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@
1616

1717
package androidx.test.internal.events.client;
1818

19-
import static org.hamcrest.MatcherAssert.assertThat;
20-
import static org.hamcrest.Matchers.is;
19+
import static com.google.common.truth.Truth.assertThat;
2120
import static org.mockito.Mockito.verify;
2221

22+
import androidx.test.ext.junit.runners.AndroidJUnit4;
23+
import androidx.test.services.events.internal.StackTrimmer;
2324
import androidx.test.services.events.run.TestAssumptionFailureEvent;
2425
import androidx.test.services.events.run.TestFailureEvent;
2526
import androidx.test.services.events.run.TestFinishedEvent;
@@ -39,10 +40,9 @@
3940
import org.mockito.ArgumentCaptor;
4041
import org.mockito.Mock;
4142
import org.mockito.MockitoAnnotations;
42-
import org.robolectric.RobolectricTestRunner;
4343

4444
/** Unit tests for {@link OrchestratedInstrumentationListener}. */
45-
@RunWith(RobolectricTestRunner.class)
45+
@RunWith(AndroidJUnit4.class)
4646
public class OrchestratedInstrumentationListenerTest {
4747
@Mock TestRunEventService testRunEventService;
4848

@@ -83,7 +83,7 @@ public void testRunFinished() throws TestEventClientException {
8383
verify(testRunEventService).send(argument.capture());
8484

8585
TestRunFinishedEvent event = (TestRunFinishedEvent) argument.getValue();
86-
assertThat(event.count, is(1));
86+
assertThat(event.count).isEqualTo(1);
8787
}
8888

8989
@Test
@@ -151,12 +151,12 @@ public void testIgnored() throws TestEventClientException {
151151

152152
private static void compareDescription(
153153
TestRunEventWithTestCase event, Description jUnitDescription) {
154-
assertThat(event.testCase.className, is(jUnitDescription.getClassName()));
155-
assertThat(event.testCase.methodName, is(jUnitDescription.getMethodName()));
154+
assertThat(event.testCase.className).isEqualTo(jUnitDescription.getClassName());
155+
assertThat(event.testCase.methodName).isEqualTo(jUnitDescription.getMethodName());
156156
}
157157

158158
private static void compareFailure(TestFailureEvent event, Failure jUnitFailure) {
159-
assertThat(event.failure.stackTrace, is(jUnitFailure.getTrace()));
159+
assertThat(event.failure.stackTrace).isEqualTo(StackTrimmer.getTrimmedStackTrace(jUnitFailure));
160160
compareDescription(event, jUnitFailure.getDescription());
161161
}
162162
}

runner/android_junit_runner/javatests/androidx/test/internal/runner/listener/InstrumentationResultPrinterTest.java

+1-23
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package androidx.test.internal.runner.listener;
1818

19-
import static androidx.test.internal.runner.listener.InstrumentationResultPrinter.MAX_TRACE_SIZE;
2019
import static androidx.test.internal.runner.listener.InstrumentationResultPrinter.REPORT_KEY_STACK;
2120
import static junit.framework.Assert.assertEquals;
2221
import static junit.framework.Assert.assertTrue;
@@ -63,27 +62,6 @@ public void sendStatus(int code, Bundle bundle) {
6362
assertTrue(resultBundle[0].containsKey(REPORT_KEY_STACK));
6463
}
6564

66-
@Test
67-
public void verifyFailureStackTraceIsTruncated() throws Exception {
68-
InstrumentationResultPrinter intrResultPrinter = new InstrumentationResultPrinter();
69-
intrResultPrinter.testNum = 1;
70-
71-
Failure testFailure = new Failure(Description.EMPTY, new Exception(getVeryLargeString()));
72-
intrResultPrinter.testFailure(testFailure);
73-
74-
int testResultTraceLength =
75-
intrResultPrinter.testResult.getString(REPORT_KEY_STACK).length() - 1;
76-
assertTrue(
77-
String.format(
78-
"The stack trace length: %s, exceeds the max: %s",
79-
testResultTraceLength, MAX_TRACE_SIZE),
80-
testResultTraceLength <= MAX_TRACE_SIZE);
81-
}
82-
83-
private static String getVeryLargeString() {
84-
return new String(new char[1000000]);
85-
}
86-
8765
@Test
8866
public void verifyFailureDescriptionPropagatedToStartAndFinishMethods() throws Exception {
8967
Description[] descriptions = new Description[2];
@@ -101,7 +79,7 @@ public void testFinished(Description description) throws Exception {
10179
};
10280

10381
Description d = Description.createTestDescription(this.getClass(), "Failure Description");
104-
Failure testFailure = new Failure(d, new Exception(getVeryLargeString()));
82+
Failure testFailure = new Failure(d, new Exception());
10583
intrResultPrinter.testFailure(testFailure);
10684

10785
assertEquals(d, descriptions[0]);

runner/android_junit_runner/javatests/androidx/test/orchestrator/junit/BundleJUnitUtilsTest.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import android.os.Parcel;
2424
import androidx.test.ext.junit.runners.AndroidJUnit4;
2525
import androidx.test.orchestrator.SampleJUnitTest;
26+
import androidx.test.services.events.internal.StackTrimmer;
2627
import org.junit.Test;
2728
import org.junit.runner.Description;
2829
import org.junit.runner.Result;
@@ -57,7 +58,7 @@ public void fromFailure() {
5758
BundleJUnitUtils.getFailure(
5859
parcelBundle(BundleJUnitUtils.getBundleFromFailure(jUnitFailure)));
5960

60-
assertThat(parcelableFailure.getTrace(), is(jUnitFailure.getTrace()));
61+
assertThat(parcelableFailure.getTrace(), is(StackTrimmer.getTrimmedStackTrace(jUnitFailure)));
6162
compareDescription(parcelableFailure.getDescription(), jUnitFailure.getDescription());
6263
}
6364

@@ -122,7 +123,7 @@ private static void compareDescription(
122123
}
123124

124125
private static void compareFailure(ParcelableFailure parcelableFailure, Failure jUnitFailure) {
125-
assertThat(parcelableFailure.getTrace(), is(jUnitFailure.getTrace()));
126+
assertThat(parcelableFailure.getTrace(), is(StackTrimmer.getTrimmedStackTrace(jUnitFailure)));
126127
compareDescription(parcelableFailure.getDescription(), jUnitFailure.getDescription());
127128
}
128129

services/events/java/androidx/test/services/events/ParcelableConverter.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import androidx.annotation.NonNull;
2222
import androidx.annotation.Nullable;
2323
import android.util.Log;
24+
import androidx.test.services.events.internal.StackTrimmer;
2425
import java.lang.annotation.Annotation;
2526
import java.lang.reflect.Array;
2627
import java.lang.reflect.Method;
@@ -99,7 +100,7 @@ public static FailureInfo getFailure(@NonNull Failure junitFailure) throws TestE
99100
return new FailureInfo(
100101
junitFailure.getMessage(),
101102
junitFailure.getTestHeader(),
102-
junitFailure.getTrace(),
103+
StackTrimmer.getTrimmedStackTrace(junitFailure),
103104
getTestCaseFromDescription(junitFailure.getDescription()));
104105
}
105106

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (C) 2020 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 androidx.test.services.events.internal;
17+
18+
import androidx.annotation.VisibleForTesting;
19+
import android.util.Log;
20+
import org.junit.runner.notification.Failure;
21+
22+
/** A utility for JUnit failure stack traces */
23+
public final class StackTrimmer {
24+
25+
private static final String TAG = "StackTrimmer";
26+
27+
@VisibleForTesting static final int MAX_TRACE_SIZE = 64 * 1024;
28+
29+
private StackTrimmer() {}
30+
31+
/**
32+
* Returns the stack trace, trimming to remove frames from the test runner, and truncating if its
33+
* too large.
34+
*/
35+
public static String getTrimmedStackTrace(Failure failure) {
36+
// TODO(b/128614857): switch to JUnit 4.13 Failure.getTrimmedTrace once its available
37+
String trace = Throwables.getTrimmedStackTrace(failure.getException());
38+
if (trace.length() > MAX_TRACE_SIZE) {
39+
// Since AJUR needs to report failures back to AM via a binder IPC, we need to make sure that
40+
// we don't exceed the Binder transaction limit - which is 1MB per process.
41+
Log.w(
42+
TAG,
43+
String.format("Stack trace too long, trimmed to first %s characters.", MAX_TRACE_SIZE));
44+
trace = trace.substring(0, MAX_TRACE_SIZE) + "\n";
45+
}
46+
return trace;
47+
}
48+
}

0 commit comments

Comments
 (0)