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 android.util.Log;
20 
21 import com.android.compatibility.common.util.ReportLog;
22 import com.android.compatibility.common.util.ResultType;
23 import com.android.compatibility.common.util.ResultUnit;
24 
25 import com.google.common.annotations.VisibleForTesting;
26 import com.google.common.collect.ImmutableMap;
27 
28 import java.util.HashMap;
29 import java.util.Map;
30 
31 /**
32  * Performance Class Requirement maps and req id to a set of {@link RequiredMeasurement}.
33  */
34 public abstract class Requirement {
35     private static final String TAG = Requirement.class.getSimpleName();
36 
37     protected final ImmutableMap<String, RequiredMeasurement<?>> mRequiredMeasurements;
38     protected final String id;
39 
Requirement(String id, RequiredMeasurement<?>[] reqs)40     protected Requirement(String id, RequiredMeasurement<?>[] reqs) {
41         this.id = id;
42 
43         ImmutableMap.Builder<String, RequiredMeasurement<?>> reqBuilder =
44             ImmutableMap.<String, RequiredMeasurement<?>>builder();
45         for (RequiredMeasurement<?> r: reqs) {
46             reqBuilder.put(r.id(), r);
47         }
48         this.mRequiredMeasurements = reqBuilder.build();
49     }
50 
id()51     public String id() {
52         return this.id;
53     }
54 
55     /**
56      * Finds the highest performance class where at least one RequiremdMeasurement has result
57      * RequirementConstants.Result.MET and none have RequirementConstants.Result.UNMET
58      */
59     @VisibleForTesting
computePerformanceClass()60     protected int computePerformanceClass() {
61         Map<Integer, RequirementConstants.Result> overallPerfClassResults = new HashMap<>();
62 
63         for (RequiredMeasurement<?> rm: this.mRequiredMeasurements.values()) {
64             Map<Integer, RequirementConstants.Result> perfClassResults = rm.getPerformanceClass();
65 
66             for (Integer pc: perfClassResults.keySet()) {
67                 RequirementConstants.Result res = perfClassResults.get(pc);
68 
69                 // if one or more results are UNMET, mark the performance class as UNMET
70                 // otherwise if at least 1 of the results is MET, mark the performance class as MET
71                 if (res == RequirementConstants.Result.UNMET) {
72                     overallPerfClassResults.put(pc, RequirementConstants.Result.UNMET);
73                 } else if (!overallPerfClassResults.containsKey(pc) &&
74                         res == RequirementConstants.Result.MET) {
75                     overallPerfClassResults.put(pc, RequirementConstants.Result.MET);
76                 }
77             }
78         }
79 
80         // report the highest performance class that has been MET
81         int perfClass = 0;
82         for (int pc: overallPerfClassResults.keySet()) {
83             if (overallPerfClassResults.get(pc) == RequirementConstants.Result.MET) {
84                 perfClass = Math.max(perfClass, pc);
85             }
86         }
87         return perfClass;
88     }
89 
90     @VisibleForTesting
checkPerformanceClass(int devicePerfClass)91     protected boolean checkPerformanceClass(int devicePerfClass) {
92         boolean noResultsUnment = true;
93         for (RequiredMeasurement<?> rm: this.mRequiredMeasurements.values()) {
94             RequirementConstants.Result res = rm.meetsPerformanceClass(devicePerfClass);
95             if (res == RequirementConstants.Result.UNMET) {
96                 Log.w(Requirement.TAG, rm.toString());
97                 noResultsUnment = false;
98             } else {
99                 Log.i(Requirement.TAG, rm.toString());
100             }
101         }
102         return noResultsUnment;
103     }
104 
setMeasuredValue(String measurement, T measuredValue)105     protected <T> void setMeasuredValue(String measurement, T measuredValue) {
106         RequiredMeasurement<T> rm =
107             (RequiredMeasurement<T>)this.mRequiredMeasurements.get(measurement);
108         rm.setMeasuredValue(measuredValue);
109     }
110 
111     /**
112      * @return whether or not the requirement meets the device's specified performance class
113      */
writeLogAndCheck(ReportLog log, String testName)114     public boolean writeLogAndCheck(ReportLog log, String testName) {
115         if (this.id == RequirementConstants.RTBD) {
116             // skip upload on any requirement without a specified id
117             Log.i(this.TAG, testName + "has requirement without set requirement id and test " +
118                 "results were not uploaded");
119             return this.checkPerformanceClass(Utils.getPerfClass());
120         }
121 
122         int perfClass = this.computePerformanceClass();
123 
124         log.addValue(RequirementConstants.TN_FIELD_NAME, testName, ResultType.NEUTRAL,
125             ResultUnit.NONE);
126         for (RequiredMeasurement rm: this.mRequiredMeasurements.values()) {
127             rm.writeValue(log);
128         }
129         log.addValue(RequirementConstants.PC_FIELD_NAME, perfClass, ResultType.NEUTRAL,
130             ResultUnit.NONE);
131 
132         return this.checkPerformanceClass(Utils.getPerfClass());
133     }
134 }
135