Skip to content

Commit d3a3a78

Browse files
brettchabotcopybara-androidxtest
authored andcommitted
Move ShardingFilter to androidx.test.filters.
PiperOrigin-RevId: 831630355
1 parent 6bad31d commit d3a3a78

File tree

7 files changed

+217
-280
lines changed

7 files changed

+217
-280
lines changed

runner/android_junit_runner/java/androidx/test/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ java_library(
6060
"//visibility:public",
6161
],
6262
deps = [
63+
"//opensource:androidsdk_compiletime",
6364
"//opensource/androidx:annotation",
6465
"@maven//:junit_junit",
6566
],
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package androidx.test.filters;
2+
3+
import android.os.Build.VERSION;
4+
import androidx.annotation.Nullable;
5+
import androidx.annotation.RestrictTo;
6+
import androidx.annotation.RestrictTo.Scope;
7+
import java.util.Objects;
8+
import org.junit.runner.Description;
9+
10+
/**
11+
* A JUnit {@link Filter} that implements SdkSuppress annotation based filtering.
12+
*
13+
* @hide
14+
*/
15+
@RestrictTo(Scope.LIBRARY)
16+
public final class SdkSuppressFilter extends AbstractFilter {
17+
18+
@Override
19+
protected boolean evaluateTest(Description description) {
20+
final SdkSuppress sdkSuppress = getAnnotationForTest(description);
21+
if (sdkSuppress != null) {
22+
if ((VERSION.SDK_INT >= sdkSuppress.minSdkVersion()
23+
&& VERSION.SDK_INT <= sdkSuppress.maxSdkVersion()
24+
&& !isInExcludedSdks(sdkSuppress.excludedSdks()))
25+
|| Objects.equals(sdkSuppress.codeName(), VERSION.CODENAME)) {
26+
return true; // run the test
27+
}
28+
return false; // don't run the test
29+
}
30+
return true; // no SdkSuppress, run the test
31+
}
32+
33+
@Nullable
34+
private SdkSuppress getAnnotationForTest(Description description) {
35+
final SdkSuppress s = description.getAnnotation(SdkSuppress.class);
36+
if (s != null) {
37+
return s;
38+
}
39+
final Class<?> testClass = description.getTestClass();
40+
if (testClass != null) {
41+
return testClass.getAnnotation(SdkSuppress.class);
42+
}
43+
return null;
44+
}
45+
46+
/** {@inheritDoc} */
47+
@Override
48+
public String describe() {
49+
return "skip tests annotated with SdkSuppress if necessary";
50+
}
51+
52+
private boolean isInExcludedSdks(int[] excludedSdks) {
53+
for (int sdk : excludedSdks) {
54+
if (sdk == VERSION.SDK_INT) {
55+
return true;
56+
}
57+
}
58+
return false;
59+
}
60+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package androidx.test.filters;
2+
3+
import androidx.annotation.RestrictTo;
4+
import androidx.annotation.RestrictTo.Scope;
5+
import org.junit.runner.Description;
6+
import org.junit.runner.manipulation.Filter;
7+
8+
/**
9+
* A JUnit sharding filter uses the hashcode of the test description to assign it to a shard.
10+
*
11+
* @hide
12+
*/
13+
@RestrictTo(Scope.LIBRARY)
14+
public class ShardingFilter extends Filter {
15+
private final int numShards;
16+
private final int shardIndex;
17+
18+
public ShardingFilter(int numShards, int shardIndex) {
19+
this.numShards = numShards;
20+
this.shardIndex = shardIndex;
21+
}
22+
23+
@Override
24+
public boolean shouldRun(Description description) {
25+
if (description.isTest()) {
26+
return (Math.floorMod(description.hashCode(), numShards)) == shardIndex;
27+
}
28+
29+
// The description is a suite, so assume that it can be run so that filtering is
30+
// applied to its children. If after filtering it has no children then it will be
31+
// automatically filtered out.
32+
return true;
33+
}
34+
35+
/** {@inheritDoc} */
36+
@Override
37+
public String describe() {
38+
return String.format("Shard %d of %d shards", shardIndex, numShards);
39+
}
40+
}

runner/android_junit_runner/java/androidx/test/internal/runner/TestRequestBuilder.java

Lines changed: 5 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,21 @@
1717
package androidx.test.internal.runner;
1818

1919
import android.app.Instrumentation;
20+
import android.os.Build;
2021
import android.os.Bundle;
2122
import android.util.Log;
2223
import androidx.annotation.VisibleForTesting;
2324
import androidx.test.filters.AbstractFilter;
2425
import androidx.test.filters.CustomFilter;
2526
import androidx.test.filters.RequiresDevice;
26-
import androidx.test.filters.SdkSuppress;
27+
import androidx.test.filters.SdkSuppressFilter;
28+
import androidx.test.filters.ShardingFilter;
2729
import androidx.test.filters.TestsRegExFilter;
2830
import androidx.test.internal.runner.ClassPathScanner.ChainedClassNameFilter;
2931
import androidx.test.internal.runner.ClassPathScanner.ExcludeClassNamesFilter;
3032
import androidx.test.internal.runner.ClassPathScanner.ExcludePackageNameFilter;
3133
import androidx.test.internal.runner.ClassPathScanner.ExternalClassNameFilter;
3234
import androidx.test.internal.runner.ClassPathScanner.InclusivePackageNamesFilter;
33-
import androidx.test.internal.util.Checks;
3435
import androidx.tracing.Trace;
3536
import java.io.IOException;
3637
import java.lang.annotation.Annotation;
@@ -84,7 +85,6 @@ public class TestRequestBuilder {
8485
.intersect(new CustomFilters());
8586
private List<Class<? extends RunnerBuilder>> customRunnerBuilderClasses = new ArrayList<>();
8687
private boolean skipExecution = false;
87-
private final DeviceBuild deviceBuild;
8888
private long perTestTimeout = 0;
8989
private ClassLoader classLoader;
9090

@@ -96,39 +96,6 @@ public class TestRequestBuilder {
9696
*/
9797
private boolean ignoreSuiteMethods = false;
9898

99-
/**
100-
* Accessor interface for retrieving device build properties.
101-
*
102-
* <p>Used so unit tests can mock calls
103-
*/
104-
interface DeviceBuild {
105-
/** Returns the SDK API level for current device. */
106-
int getSdkVersionInt();
107-
108-
/** Returns the hardware type of the current device. */
109-
String getHardware();
110-
111-
/** Returns the version code name of the current device. */
112-
String getCodeName();
113-
}
114-
115-
private static class DeviceBuildImpl implements DeviceBuild {
116-
@Override
117-
public int getSdkVersionInt() {
118-
return android.os.Build.VERSION.SDK_INT;
119-
}
120-
121-
@Override
122-
public String getHardware() {
123-
return android.os.Build.HARDWARE;
124-
}
125-
126-
@Override
127-
public String getCodeName() {
128-
return android.os.Build.VERSION.CODENAME;
129-
}
130-
}
131-
13299
/** Filter that only runs tests whose method or class has been annotated with given filter. */
133100
private static class AnnotationInclusionFilter extends AbstractFilter {
134101

@@ -277,42 +244,6 @@ public String describe() {
277244
}
278245
}
279246

280-
private class SdkSuppressFilter extends AbstractFilter {
281-
282-
@Override
283-
protected boolean evaluateTest(Description description) {
284-
final SdkSuppress sdkSuppress = getAnnotationForTest(description);
285-
if (sdkSuppress != null) {
286-
if ((getDeviceSdkInt() >= sdkSuppress.minSdkVersion()
287-
&& getDeviceSdkInt() <= sdkSuppress.maxSdkVersion()
288-
&& !isInExcludedSdks(sdkSuppress.excludedSdks()))
289-
|| getDeviceCodeName().equals(sdkSuppress.codeName())) {
290-
return true; // run the test
291-
}
292-
return false; // don't run the test
293-
}
294-
return true; // no SdkSuppress, run the test
295-
}
296-
297-
private SdkSuppress getAnnotationForTest(Description description) {
298-
final SdkSuppress s = description.getAnnotation(SdkSuppress.class);
299-
if (s != null) {
300-
return s;
301-
}
302-
final Class<?> testClass = description.getTestClass();
303-
if (testClass != null) {
304-
return testClass.getAnnotation(SdkSuppress.class);
305-
}
306-
return null;
307-
}
308-
309-
/** {@inheritDoc} */
310-
@Override
311-
public String describe() {
312-
return String.format("skip tests annotated with SdkSuppress if necessary");
313-
}
314-
}
315-
316247
/** Class that filters out tests annotated with {@link RequiresDevice} when running on emulator */
317248
@VisibleForTesting
318249
class RequiresDeviceFilter extends AnnotationExclusionFilter {
@@ -335,7 +266,7 @@ class RequiresDeviceFilter extends AnnotationExclusionFilter {
335266
protected boolean evaluateTest(Description description) {
336267
if (!super.evaluateTest(description)) {
337268
// annotation is present - check if device is an emulator
338-
return !emulatorHardwareNames.contains(getDeviceHardware());
269+
return !emulatorHardwareNames.contains(Build.HARDWARE);
339270
}
340271
return true;
341272
}
@@ -347,34 +278,6 @@ public String describe() {
347278
}
348279
}
349280

350-
private static class ShardingFilter extends Filter {
351-
private final int numShards;
352-
private final int shardIndex;
353-
354-
ShardingFilter(int numShards, int shardIndex) {
355-
this.numShards = numShards;
356-
this.shardIndex = shardIndex;
357-
}
358-
359-
@Override
360-
public boolean shouldRun(Description description) {
361-
if (description.isTest()) {
362-
return (Math.abs(description.hashCode()) % numShards) == shardIndex;
363-
}
364-
365-
// The description is a suite, so assume that it can be run so that filtering is
366-
// applied to its children. If after filtering it has no children then it will be
367-
// automatically filtered out.
368-
return true;
369-
}
370-
371-
/** {@inheritDoc} */
372-
@Override
373-
public String describe() {
374-
return String.format("Shard %s of %s shards", shardIndex, numShards);
375-
}
376-
}
377-
378281
/**
379282
* A {@link Request} that doesn't report an error if all tests are filtered out. Done for
380283
* consistency with InstrumentationTestRunner.
@@ -536,18 +439,10 @@ public TestRequestBuilder(Instrumentation instr, Bundle bundle) {
536439

537440
/** Creates a TestRequestBuilder */
538441
public TestRequestBuilder() {
539-
this(new DeviceBuildImpl());
540-
}
541-
542-
/** Alternate TestRequestBuilder constructor that accepts a custom DeviceBuild */
543-
@VisibleForTesting
544-
TestRequestBuilder(DeviceBuild deviceBuildAccessor) {
545-
deviceBuild = Checks.checkNotNull(deviceBuildAccessor);
546-
547442
maybeAddLegacySuppressFilter();
548443
}
549444

550-
// add legacy Suppress filer iff it is on classpath
445+
// add legacy Suppress filter iff it is on classpath
551446
private void maybeAddLegacySuppressFilter() {
552447
try {
553448
Class<? extends Annotation> legacySuppressClass =
@@ -929,25 +824,4 @@ private Class<? extends Annotation> loadAnnotationClass(String className) {
929824
}
930825
return null;
931826
}
932-
933-
private int getDeviceSdkInt() {
934-
return deviceBuild.getSdkVersionInt();
935-
}
936-
937-
private String getDeviceHardware() {
938-
return deviceBuild.getHardware();
939-
}
940-
941-
private String getDeviceCodeName() {
942-
return deviceBuild.getCodeName();
943-
}
944-
945-
private boolean isInExcludedSdks(int[] excludedSdks) {
946-
for (int sdk : excludedSdks) {
947-
if (sdk == getDeviceSdkInt()) {
948-
return true;
949-
}
950-
}
951-
return false;
952-
}
953827
}

0 commit comments

Comments
 (0)