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.mediapc.cts.common; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.Truth.assertWithMessage; 21 22 import static org.junit.Assume.assumeTrue; 23 24 import android.util.Log; 25 26 import androidx.annotation.NonNull; 27 import androidx.annotation.VisibleForTesting; 28 import androidx.test.platform.app.InstrumentationRegistry; 29 30 import com.android.compatibility.common.util.DeviceReportLog; 31 import com.android.cts.verifier.CtsVerifierReportLog; 32 33 import com.google.common.base.Preconditions; 34 35 import org.junit.rules.TestName; 36 37 import java.util.HashSet; 38 import java.util.Map; 39 import java.util.Set; 40 import java.util.stream.Collectors; 41 42 /** 43 * Logs a set of measurements and results for defined performance class requirements. 44 * 45 * <p> Nested classes are organized alphabetically, add[Requirement] functions are organized by 46 * their requirement number in the order they appear in the Android CDD 47 */ 48 public class PerformanceClassEvaluator { 49 private static final String TAG = PerformanceClassEvaluator.class.getSimpleName(); 50 51 private final String mTestName; 52 private Set<Requirement> mRequirements; 53 PerformanceClassEvaluator(TestName testName)54 public PerformanceClassEvaluator(TestName testName) { 55 Preconditions.checkNotNull(testName); 56 String baseTestName = testName.getMethodName() != null ? testName.getMethodName() : ""; 57 this.mTestName = baseTestName.replace("{", "(").replace("}", ")"); 58 this.mRequirements = new HashSet<Requirement>(); 59 } 60 getTestName()61 String getTestName() { 62 return mTestName; 63 } 64 addRequirement(R req)65 public <R extends Requirement> R addRequirement(R req) { 66 if (!this.mRequirements.add(req)) { 67 throw new IllegalStateException("Requirement " + req.id() + " already added"); 68 } 69 return req; 70 } 71 72 /** 73 * Returns if the PerformanceClassEvaluator is ready to be submitted. 74 * 75 * <p>The PerformanceClassEvaluator is ready for submission if: all added requirements have all 76 * their required measurements recorded AND there is at least one requirement added. 77 * 78 * <p>Note: this function is ONLY meant to be used by ITS. Other tests should attempt to submit 79 * and make sure an exception is not thrown during submission. 80 */ isReadyToSubmitItsResults()81 public boolean isReadyToSubmitItsResults() { 82 boolean allMeasuredValuesSet = 83 mRequirements.stream().allMatch(r -> r.allMeasuredValuesSet()); 84 boolean hasRequirements = !mRequirements.isEmpty(); 85 return allMeasuredValuesSet && hasRequirements; 86 } 87 88 private enum SubmitType { 89 TRADEFED, VERIFIER 90 } 91 92 submitAndCheck()93 public void submitAndCheck() { 94 // submit clears the requirements so compute before submitting 95 Map<Requirement, Integer> idToGrade = computeGrades(); 96 boolean perfClassMet = submit(SubmitType.TRADEFED); 97 // check performance class 98 assumeTrue("Build.VERSION.MEDIA_PERFORMANCE_CLASS is not declared", Utils.isPerfClass()); 99 if (!perfClassMet) { 100 idToGrade.forEach( 101 (r, grade) -> { 102 int pc = Utils.getPerfClass(); 103 if (r.appliesToPerformanceClass(pc)) { 104 assertWithMessage("%s performance class", r).that(grade).isAtLeast(pc); 105 } 106 }); 107 } 108 // Safety catch. 109 assertThat(perfClassMet).isTrue(); 110 } 111 submitAndVerify()112 public void submitAndVerify() { 113 // submit clears the requirements so compute before submitting 114 Map<Requirement, Integer> grades = computeGrades(); 115 boolean perfClassMet = submit(SubmitType.VERIFIER); 116 int declaredPc = Utils.getPerfClass(); 117 118 if (!perfClassMet && Utils.isPerfClass()) { 119 String msg = "Declared performance class %s but requirement [%s] grades as %s"; 120 grades.forEach((r, grade) -> Log.w(TAG, msg.formatted(declaredPc, r, grade))); 121 } 122 } 123 124 @NonNull 125 @VisibleForTesting // Prevents warning about using computePerformanceClass computeGrades()126 private Map<Requirement, Integer> computeGrades() { 127 return mRequirements.stream() 128 .collect(Collectors.toMap(r -> r, Requirement::computePerformanceClass)); 129 } 130 submit(SubmitType type)131 private boolean submit(SubmitType type) { 132 boolean perfClassMet = true; 133 for (Requirement req : this.mRequirements) { 134 switch (type) { 135 case VERIFIER: 136 CtsVerifierReportLog verifierLog = new CtsVerifierReportLog( 137 RequirementConstants.REPORT_LOG_NAME, req.id()); 138 perfClassMet &= req.writeLogAndCheck(verifierLog, this.mTestName); 139 verifierLog.submit(); 140 break; 141 142 case TRADEFED: 143 default: 144 DeviceReportLog tradefedLog = new DeviceReportLog( 145 RequirementConstants.REPORT_LOG_NAME, req.id()); 146 perfClassMet &= req.writeLogAndCheck(tradefedLog, this.mTestName); 147 tradefedLog.submit(InstrumentationRegistry.getInstrumentation()); 148 break; 149 } 150 } 151 this.mRequirements.clear(); // makes sure report isn't submitted twice 152 return perfClassMet; 153 } 154 } 155