1 /* 2 * Copyright (C) 2022 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 17 package android.platform.test.rule; 18 19 20 import androidx.test.platform.app.InstrumentationRegistry; 21 import androidx.test.uiautomator.UiDevice; 22 23 import org.junit.AssumptionViolatedException; 24 import org.junit.rules.TestRule; 25 import org.junit.runner.Description; 26 import org.junit.runners.model.Statement; 27 28 import java.io.IOException; 29 import java.lang.annotation.ElementType; 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 import java.lang.annotation.Target; 33 import java.util.Arrays; 34 35 /** 36 * Rule that runs tests marked with @Presubmit on presubmit test runs, only on devices listed in the 37 * comma-separated string passed as an argument to the @Presubmit annotation. The test will be 38 * skipped, for presubmit runs, on devices not in the list. 39 */ 40 public class PresubmitRule implements TestRule { 41 42 /** 43 * For test running in config that implements the instrumentation argument is-presubmit (such as 44 * cl/663453103), return true if the test is actually running in presubmit. 45 * 46 * <p>Otherwise, return true if there is a parameter to exclude postsubmit. 47 */ runningInPresubmit()48 public static boolean runningInPresubmit() { 49 final String isPresubmit = 50 InstrumentationRegistry.getArguments().getString("is-presubmit", "unknown"); 51 if (isPresubmit.equals("true")) { 52 return true; 53 } else if (isPresubmit.equals("false")) { 54 return false; 55 } 56 57 // We run in presubmit when there is a parameter to exclude postsubmits. 58 final String nonAnnotationArgument = 59 InstrumentationRegistry.getArguments().getString("notAnnotation", ""); 60 return Arrays.asList(nonAnnotationArgument.split(",")) 61 .contains("android.platform.test.annotations.Postsubmit"); 62 } 63 64 @Override apply(Statement base, Description description)65 public Statement apply(Statement base, Description description) { 66 // If the test is not annotated with @Presubmit, this rule is not applicable. 67 final Presubmit annotation = description.getTestClass().getAnnotation(Presubmit.class); 68 if (annotation == null) return base; 69 70 // If the test suite isn't running with 71 // "exclude-annotation": "android.platform.test.annotations.Postsubmit", then this is not 72 // a presubmit test, and the rule is not applicable. 73 if (!runningInPresubmit()) { 74 return base; 75 } 76 77 final String flavor; 78 try { 79 flavor = 80 UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) 81 .executeShellCommand("getprop ro.build.flavor") 82 .replaceAll("\\s", "") 83 .replace("-userdebug", ""); 84 } catch (IOException e) { 85 throw new RuntimeException(e); 86 } 87 88 // If the target IS listed in the annotation's parameter, this rule is not applicable. 89 final boolean match = Arrays.asList(annotation.value().split(",")).contains(flavor); 90 if (match) return base; 91 92 // The test will be skipped upon start. 93 return new Statement() { 94 @Override 95 public void evaluate() throws Throwable { 96 throw new AssumptionViolatedException( 97 "Skipping the test on target " 98 + flavor 99 + " which in not in " 100 + annotation.value()); 101 } 102 }; 103 } 104 105 @Retention(RetentionPolicy.RUNTIME) 106 @Target({ElementType.TYPE}) 107 public @interface Presubmit { 108 String value(); 109 } 110 } 111