1# Writing an MPC Test 2 3Using 4[this CL](https://android-review.googlesource.com/c/platform/cts/+/2128521) as a 5guide focusing on requirement 6[8.2/H-1-1](https://source.android.com/docs/compatibility/13/android-13-cdd#2274_performance): 7 8- R: MUST ensure a sequential write performance of at least 100MB/s. 9- S and Tiramisu: MUST ensure a sequential write performance of at least 10 125MB/s. 11 12## Define Requirements 13 14### Define Constants Under RequirementConstants 15 16For our requirement, 17[8.2/H-1-1](https://source.android.com/docs/compatibility/13/android-13-cdd#2274_performance), 18we have one required measurement, so we will create one constant, 19`FILESYSTEM_IO_RATE`, to track that. This constant eventually will make its way 20to the internal cts_media_performance_class_test_metrics.proto, so the 21string-value we choose for it needs to structured like a proto field name and 22should include units at the end: 23 24``` 25public static final String FILESYSTEM_IO_RATE = "filesystem_io_rate_mbps"; 26``` 27 28Additionally, we may need to create a new BiPredicate for our requirement. The 29BiPredicate defines the operator to test measurements for our requirement with. 30For our case, we want to test if an I/O rate is at or above a certain value, so 31we will use a GTE operator. We will additionally be storing I/O rates as 32doubles, leading us to define the BiPredicate DOUBLE_GTE: 33 34``` 35public static final BiPredicate<Double, Double> DOUBLE_GTE = RequirementConstants.gte(); 36``` 37 38### Define Requirement Class Under PerformanceClassEvaluator 39 40In PerformanceClassEvaluator.java, we will define a new requirement class. This 41class should be defined as nested class under PerformanceClassEvaluator: 42 43``` 44// used for requirements [8.2/H-1-1], [8.2/H-1-2], [8.2/H-1-3], [8.2/H-1-4] 45public static class FileSystemRequirement extends Requirement { 46 47 private static final String TAG = FileSystemRequirement.class.getSimpleName(); 48 49 ... 50 51} 52``` 53 54#### Define Constructor 55 56The constructors for requirement classes are very standardized. They are always 57private; they always take in two inputs: `String id, RequiredMeasurement<?> ... 58reqs`; and they always contain one line: `super(id, reqs)`: 59 60``` 61private FileSystemRequirement(String id, RequiredMeasurement<?> ... reqs) { 62 super(id, reqs); 63} 64``` 65 66#### Define Set Measured Value Method(s) 67 68Requirement classes need to define a method for each required measurement. These 69methods always contain one line: a function call to Requirement’s 70`setMeausredValue` method. For 71[8.2/H-1-1](https://source.android.com/docs/compatibility/13/android-13-cdd#2274_performance), 72we only have one required measurement so only need to make one method for it: 73 74``` 75/** 76 * Set the Filesystem I/O Rate in MB/s. 77 */ 78public void setFilesystemIoRate(double filesystemIoRate) { 79 this.setMeasuredValue(RequirementConstants.FILESYSTEM_IO_RATE, filesystemIoRate); 80} 81``` 82 83#### Define Create Method 84 85The last thing we need to make for our requirement class is a create method. 86This method defines each of the required measurements. Each 87RequiredMeasurement.java is created through a builder and defining the 88following: 89 90* The datatype of the measurement. This is during the call to the 91 RequiredMeasurement’s builder function, ex: `<Double>builder()` 92* The ID for the measurement. This is the String constant we defined earlier. 93* The predicate for the measurement. This is the BiPredicate we defined 94 earlier. 95* A required value for each achievable performance class. For example, using 96 the GTE a BiPredicate: 97 * `addRequiredValue(Build.VERSION_CODES.R, 100.0)` says that if a 98 requirement measurement is greater than or equal to to 100, the device 99 makes performance class R 100 * `addRequiredValue(Build.VERSION_CODES.TIRAMISU, 125.0)` says that if a 101 requirement measurement is greater than or equal to to 125, the device 102 makes performance class Tiramisu 103 104Note: if a device meets multiple performance classes for a requirement, the 105system automatically chooses to record the higher classification 106 107For requirement 108[8.2/H-1-1](https://source.android.com/docs/compatibility/13/android-13-cdd#2274_performance) 109we define the following create method: 110 111``` 112/** 113 * [8.2/H-1-1] MUST ensure a sequential write performance of 114 * at least 100(R) / 125(S & T) MB/s. 115 */ 116public static FileSystemRequirement createR8_2__H_1_1() { 117 RequiredMeasurement<Double> filesystem_io_rate = 118 RequiredMeasurement.<Double>builder() 119 .setId(RequirementConstants.FILESYSTEM_IO_RATE) 120 .setPredicate(RequirementConstants.DOUBLE_GTE) 121 .addRequiredValue(Build.VERSION_CODES.R, 100.0) 122 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 125.0) 123 .build(); 124 125 return new FileSystemRequirement(RequirementConstants.R8_2__H_1_1, 126 filesystem_io_rate); 127} 128``` 129 130Note: a requirement class can be and often is used for multiple requirements. If 131so, a create method must be defined for each. 132 133#### Define Add Method at the Bottom of PerformanceClassEvaluator 134 135After all of that we just need to define an add method at the bottom of 136PerformacneClassEvaluator for our requirement. All it does is call 137PerformanceClassEvaluator’s `addRequirement` method using the create method we 138defined earlier. 139 140``` 141public FileSystemRequirement addR8_2__H_1_1() { 142 return this.addRequirement(FileSystemRequirement.createR8_2__H_1_1()); 143} 144``` 145 146## Update Test to Report Data Using PerformanceClassEvaluator 147 148Now that we have a requirement defined we just need to update our test to use 149PerformanceClassEvaluator. 150 151First we need to add the following to our test class: @Rule public final 152TestName mTestName = new TestName(); 153 154Next we will create the evaluator and add our newly defined requirement. This 155can be done at any point during the test, but typically test writers choose to 156do this at the end of the test: 157 158``` 159PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName); 160PerformanceClassEvaluator.FileSystemRequirement r8_2__H_1_1 = pce.addR8_2__H_1_1(); 161``` 162 163After the test, once our required measurement(s) have been calculated, we use 164the set measurement method(s) we defined to report them: 165 166``` 167r8_2__H_1_1.setFilesystemIoRate(stat.mAverage); 168``` 169 170Finally, we just need to submit our results. The submit method should be called 171only once at the very end of the test. If we are writing our test CTS, we should 172use `submitAndCheck`; if we are writing our test under CTS-Verifier or ITS, we 173should use `submitAndVerify`. Ex: 174 175``` 176pce.submitAndCheck(); 177``` 178 179The test results are then processed and reported creating a file 180cts_media_performance_class_test_cases.reportlog.json which will eventually have 181its data upload and processed. 182 183You can view the file with 184 185```shell 186adb root 187adb shell cat /storage/emulated/0/report-log-files/CtsMediaPerformanceClassTestCases.reportlog.json 188``` 189