Home | History | Annotate | Download | only in rtt
      1 /*
      2  * Copyright (C) 2018 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 com.android.server.wifi.rtt;
     18 
     19 import static org.hamcrest.core.IsEqual.equalTo;
     20 import static org.mockito.Mockito.when;
     21 
     22 import android.hardware.wifi.V1_0.RttResult;
     23 import android.hardware.wifi.V1_0.RttStatus;
     24 import android.net.MacAddress;
     25 import android.net.wifi.rtt.RangingRequest;
     26 import android.net.wifi.rtt.ResponderConfig;
     27 import android.os.WorkSource;
     28 import android.util.Log;
     29 
     30 import com.android.server.wifi.Clock;
     31 import com.android.server.wifi.nano.WifiMetricsProto;
     32 
     33 import org.junit.Before;
     34 import org.junit.Rule;
     35 import org.junit.Test;
     36 import org.junit.rules.ErrorCollector;
     37 import org.mockito.Mock;
     38 import org.mockito.MockitoAnnotations;
     39 
     40 import java.io.PrintWriter;
     41 import java.io.StringWriter;
     42 import java.util.ArrayList;
     43 import java.util.List;
     44 
     45 /**
     46  * Unit test harness for RttMetrics
     47  */
     48 public class RttMetricsTest {
     49     private RttMetrics mDut;
     50 
     51     @Mock
     52     Clock mClock;
     53 
     54     @Rule
     55     public ErrorCollector collector = new ErrorCollector();
     56 
     57     /**
     58      * Pre-test configuration. Initialize and install mocks.
     59      */
     60     @Before
     61     public void setUp() throws Exception {
     62         MockitoAnnotations.initMocks(this);
     63 
     64         setTime(1);
     65         mDut = new RttMetrics(mClock);
     66     }
     67 
     68     /**
     69      * Verify that recordRequest() records valid metrics.
     70      */
     71     @Test
     72     public void testRecordRequest() {
     73         WifiMetricsProto.WifiRttLog log;
     74 
     75         // no requests
     76         log = mDut.consolidateProto();
     77         checkMainStats("No requests", log, 0, 0);
     78         checkPeerStats("No requests: AP", log.rttToAp, 0, 0, 0, 0, 0, 0, 0, 0);
     79         checkPeerStats("No requests: Aware", log.rttToAware, 0, 0, 0, 0, 0, 0, 0, 0);
     80 
     81         // multiple AP requests from multiple sources
     82         WorkSource ws1 = new WorkSource(10);
     83         WorkSource ws2 = new WorkSource(20);
     84         ws2.add(10);
     85 
     86         RangingRequest requestAp1 = getDummyRangingRequest(1, 0);
     87         RangingRequest requestAp2 = getDummyRangingRequest(2, 0);
     88         RangingRequest requestAp5 = getDummyRangingRequest(5, 0);
     89         RangingRequest requestAp6 = getDummyRangingRequest(6, 0);
     90 
     91         mDut.clear();
     92         mDut.recordRequest(ws1, requestAp1);
     93         setTime(10); // delta = 9
     94         mDut.recordRequest(ws1, requestAp2);
     95         setTime(20); // delta = 10
     96         mDut.recordRequest(ws1, requestAp5);
     97         setTime(21); // delta = 1
     98         mDut.recordRequest(ws1, requestAp6);
     99         setTime(1000); // delta = 979
    100         mDut.recordRequest(ws1, requestAp5);
    101         setTime(5000); // delta = 4,000
    102         mDut.recordRequest(ws1, requestAp5);
    103         setTime(1000000); // delta = 995,000
    104         mDut.recordRequest(ws1, requestAp2);
    105         mDut.recordRequest(ws2, requestAp5);
    106         mDut.recordRequest(ws2, requestAp5);
    107         mDut.recordRequest(ws2, requestAp5);
    108 
    109         log = mDut.consolidateProto();
    110         checkMainStats("Sequence AP-only", log, 10, 0);
    111 
    112         checkPeerStats("Sequence AP-only: AP", log.rttToAp, 10, 41, 2, 2, 4, 0, 0, 5);
    113 
    114         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramNumRequestsPerApp[0]",
    115                 log.rttToAp.histogramNumRequestsPerApp[0], 1, 10, 1);
    116         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramNumRequestsPerApp[1]",
    117                 log.rttToAp.histogramNumRequestsPerApp[1], 10, 100, 1);
    118 
    119         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramNumPeersPerRequest[0]",
    120                 log.rttToAp.histogramNumPeersPerRequest[0], 1, 1, 1);
    121         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramNumPeersPerRequest[1]",
    122                 log.rttToAp.histogramNumPeersPerRequest[1], 2, 2, 2);
    123         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramNumPeersPerRequest[2]",
    124                 log.rttToAp.histogramNumPeersPerRequest[2], 5, 5, 6);
    125         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramNumPeersPerRequest[3]",
    126                 log.rttToAp.histogramNumPeersPerRequest[3], 6, 6, 1);
    127 
    128         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramRequestIntervalMs[0]",
    129                 log.rttToAp.histogramRequestIntervalMs[0], 1, 10, 5);
    130         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramRequestIntervalMs[1]",
    131                 log.rttToAp.histogramRequestIntervalMs[1], 10, 100, 1);
    132         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramRequestIntervalMs[2]",
    133                 log.rttToAp.histogramRequestIntervalMs[2], 100, 1000, 1);
    134         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramRequestIntervalMs[3]",
    135                 log.rttToAp.histogramRequestIntervalMs[3], 1000, 10000, 1);
    136         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramRequestIntervalMs[4]",
    137                 log.rttToAp.histogramRequestIntervalMs[4], 100000, 1000000, 1);
    138 
    139         checkPeerStats("Sequence AP-only: Aware", log.rttToAware, 0, 0, 0, 0, 0, 0, 0, 0);
    140 
    141         // mix of AP and Aware requests
    142         WorkSource ws3 = new WorkSource(30);
    143         ws3.add(20);
    144         ws3.add(40);
    145 
    146         RangingRequest requestMixed03 = getDummyRangingRequest(0, 3);
    147         RangingRequest requestMixed25 = getDummyRangingRequest(2, 5);
    148         RangingRequest requestMixed50 = getDummyRangingRequest(5, 0);
    149         RangingRequest requestMixed08 = getDummyRangingRequest(0, 8);
    150 
    151         mDut.clear();
    152         setTime(100);
    153         mDut.recordRequest(ws3, requestMixed03);
    154         setTime(101);
    155         mDut.recordRequest(ws3, requestMixed25);
    156         setTime(102);
    157         mDut.recordRequest(ws3, requestMixed50);
    158         setTime(103);
    159         mDut.recordRequest(ws3, requestMixed08);
    160 
    161         log = mDut.consolidateProto();
    162         checkMainStats("Sequence Mixed AP/Aware", log, 4, 0);
    163 
    164         checkPeerStats("Sequence Mixed AP/Aware: AP", log.rttToAp, 2, 7, 3, 1, 2, 0, 0, 1);
    165 
    166         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramNumRequestsPerApp[0]",
    167                 log.rttToAp.histogramNumRequestsPerApp[0], 1, 10, 3);
    168 
    169         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramNumPeersPerRequest[0]",
    170                 log.rttToAp.histogramNumPeersPerRequest[0], 2, 2, 1);
    171         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramNumPeersPerRequest[1]",
    172                 log.rttToAp.histogramNumPeersPerRequest[1], 5, 5, 1);
    173 
    174         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramRequestIntervalMs[0]",
    175                 log.rttToAp.histogramRequestIntervalMs[0], 1, 10, 1);
    176 
    177         checkPeerStats("Sequence Mixed AP/Aware: Aware", log.rttToAware, 3, 16, 3, 1, 3, 0, 0, 1);
    178 
    179         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramNumRequestsPerApp[0]",
    180                 log.rttToAware.histogramNumRequestsPerApp[0], 1, 10, 3);
    181 
    182         validateProtoHistBucket(
    183                 "Sequence Mixed AP/Aware: rttToAware.histogramNumPeersPerRequest[0]",
    184                 log.rttToAware.histogramNumPeersPerRequest[0], 3, 3, 1);
    185         validateProtoHistBucket(
    186                 "Sequence Mixed AP/Aware: rttToAware.histogramNumPeersPerRequest[1]",
    187                 log.rttToAware.histogramNumPeersPerRequest[1], 5, 5, 1);
    188         validateProtoHistBucket(
    189                 "Sequence Mixed AP/Aware: rttToAware.histogramNumPeersPerRequest[2]",
    190                 log.rttToAware.histogramNumPeersPerRequest[2], 8, 8, 1);
    191 
    192         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramRequestIntervalMs[0]",
    193                 log.rttToAware.histogramRequestIntervalMs[0], 1, 10, 2);
    194     }
    195 
    196     /**
    197      * Verify that recordResult() records valid metrics.
    198      */
    199     @Test
    200     public void testRecordResult() {
    201         WifiMetricsProto.WifiRttLog log;
    202 
    203         // no requests
    204         log = mDut.consolidateProto();
    205         checkMainStats("No requests", log, 0, 0);
    206         checkPeerStats("No requests: AP", log.rttToAp, 0, 0, 0, 0, 0, 0, 0, 0);
    207         checkPeerStats("No requests: Aware", log.rttToAware, 0, 0, 0, 0, 0, 0, 0, 0);
    208 
    209         // multiple AP results
    210         RangingRequest requestAp1 = getDummyRangingRequest(1, 0);
    211         RangingRequest requestAp2 = getDummyRangingRequest(2, 0);
    212         RangingRequest requestAp5 = getDummyRangingRequest(5, 0);
    213         RangingRequest requestAp6 = getDummyRangingRequest(6, 0);
    214 
    215         mDut.clear();
    216         mDut.recordResult(requestAp1, getDummyRangingResults(requestAp1, 5, 0));
    217         mDut.recordResult(requestAp2, getDummyRangingResults(requestAp2, 10, 30));
    218         mDut.recordResult(requestAp5, getDummyRangingResults(requestAp5, 0.3, -0.2));
    219         mDut.recordResult(requestAp6, getDummyRangingResults(requestAp6, 40, 30));
    220         log = mDut.consolidateProto();
    221 
    222         checkMainStats("Sequence AP-only", log, 0, 0);
    223 
    224         checkPeerStats("Sequence AP-only: AP", log.rttToAp, 0, 0, 0, 0, 0, 1, 6, 0);
    225 
    226         validateProtoIndividualStatusHistBucket(
    227                 "Sequence AP-only: rttToAp.histogramIndividualStatus[0]",
    228                 log.rttToAp.histogramIndividualStatus[0], WifiMetricsProto.WifiRttLog.SUCCESS, 14);
    229 
    230         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramDistance[0]",
    231                 log.rttToAp.histogramDistance[0], Integer.MIN_VALUE, 0, 3);
    232         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramDistance[1]",
    233                 log.rttToAp.histogramDistance[1], 0, 5 * 1000, 2);
    234         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramDistance[2]",
    235                 log.rttToAp.histogramDistance[2], 5 * 1000, 15 * 1000, 2);
    236         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramDistance[3]",
    237                 log.rttToAp.histogramDistance[3], 30 * 1000, 60 * 1000, 2);
    238         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramDistance[4]",
    239                 log.rttToAp.histogramDistance[4], 60 * 1000, 100 * 1000, 1);
    240         validateProtoHistBucket("Sequence AP-only: rttToAp.histogramDistance[5]",
    241                 log.rttToAp.histogramDistance[5], 100 * 1000, Integer.MAX_VALUE, 4);
    242 
    243         checkPeerStats("Sequence AP-only: Aware", log.rttToAware, 0, 0, 0, 0, 0, 0, 0, 0);
    244 
    245         // mix of AP and Aware requests
    246         RangingRequest requestMixed03 = getDummyRangingRequest(0, 3);
    247         RangingRequest requestMixed25 = getDummyRangingRequest(2, 5);
    248         RangingRequest requestMixed50 = getDummyRangingRequest(5, 0);
    249         RangingRequest requestMixed08 = getDummyRangingRequest(0, 8);
    250 
    251         mDut.clear();
    252         mDut.recordResult(requestMixed03, getDummyRangingResults(requestMixed03, 5, 0));
    253         mDut.recordResult(requestMixed25, getDummyRangingResults(requestMixed25, 10, 30));
    254         mDut.recordResult(requestMixed50, getDummyRangingResults(requestMixed50, 0.3, -0.2));
    255         mDut.recordResult(requestMixed08, getDummyRangingResults(requestMixed08, 40, 30));
    256         log = mDut.consolidateProto();
    257 
    258         checkMainStats("Sequence Mixed AP/Aware", log, 0, 0);
    259 
    260         checkPeerStats("Sequence Mixed AP/Aware: AP", log.rttToAp, 0, 0, 0, 0, 0, 1, 4, 0);
    261 
    262         validateProtoIndividualStatusHistBucket(
    263                 "Sequence Mixed AP/Aware: rttToAp.histogramIndividualStatus[0]",
    264                 log.rttToAp.histogramIndividualStatus[0], WifiMetricsProto.WifiRttLog.SUCCESS, 7);
    265 
    266         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramDistance[0]",
    267                 log.rttToAp.histogramDistance[0], Integer.MIN_VALUE, 0, 3);
    268         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramDistance[1]",
    269                 log.rttToAp.histogramDistance[1], 0, 5 * 1000, 2);
    270         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramDistance[2]",
    271                 log.rttToAp.histogramDistance[2], 5 * 1000, 15 * 1000, 1);
    272         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramDistance[3]",
    273                 log.rttToAp.histogramDistance[3], 30 * 1000, 60 * 1000, 1);
    274 
    275         checkPeerStats("Sequence Mixed AP/Aware: Aware", log.rttToAware, 0, 0, 0, 0, 0, 1, 4, 0);
    276 
    277         validateProtoIndividualStatusHistBucket(
    278                 "Sequence Mixed AP/Aware: rttToAware.histogramIndividualStatus[0]",
    279                 log.rttToAware.histogramIndividualStatus[0], WifiMetricsProto.WifiRttLog.SUCCESS,
    280                 16);
    281 
    282         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramDistance[0]",
    283                 log.rttToAware.histogramDistance[0], 5 * 1000, 15 * 1000, 3);
    284         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramDistance[1]",
    285                 log.rttToAware.histogramDistance[1], 30 * 1000, 60 * 1000, 1);
    286         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramDistance[2]",
    287                 log.rttToAware.histogramDistance[2], 60 * 1000, 100 * 1000, 2);
    288         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramDistance[3]",
    289                 log.rttToAware.histogramDistance[3], 100 * 1000, Integer.MAX_VALUE, 10);
    290     }
    291 
    292     /**
    293      * Verify the behavior when the HAL returns with missing results or some results set to null.
    294      */
    295     @Test
    296     public void testRecordMissingResults() {
    297         WifiMetricsProto.WifiRttLog log;
    298 
    299         mDut.clear();
    300         RangingRequest requestMixed25 = getDummyRangingRequest(2, 5);
    301         List<RttResult> resultMixed25 = getDummyRangingResults(requestMixed25, 10, 30);
    302         // remove some results
    303         resultMixed25.remove(3); // Second Aware result: distance = 100
    304         resultMixed25.remove(0); // First AP result: distance = 10
    305         resultMixed25.add(null);
    306         mDut.recordResult(requestMixed25, resultMixed25);
    307 
    308         log = mDut.consolidateProto();
    309 
    310         checkMainStats("Sequence Mixed AP/Aware", log, 0, 0);
    311 
    312         checkPeerStats("Sequence Mixed AP/Aware: AP", log.rttToAp, 0, 0, 0, 0, 0, 2, 1, 0);
    313 
    314         validateProtoIndividualStatusHistBucket(
    315                 "Sequence Mixed AP/Aware: rttToAp.histogramIndividualStatus[0]",
    316                 log.rttToAp.histogramIndividualStatus[0], WifiMetricsProto.WifiRttLog.SUCCESS, 1);
    317         validateProtoIndividualStatusHistBucket(
    318                 "Sequence Mixed AP/Aware: rttToAp.histogramIndividualStatus[1]",
    319                 log.rttToAp.histogramIndividualStatus[1],
    320                 WifiMetricsProto.WifiRttLog.MISSING_RESULT, 1);
    321 
    322         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAp.histogramDistance[0]",
    323                 log.rttToAp.histogramDistance[0], 30 * 1000, 60 * 1000, 1);
    324 
    325         checkPeerStats("Sequence Mixed AP/Aware: Aware", log.rttToAware, 0, 0, 0, 0, 0, 2, 2, 0);
    326 
    327         validateProtoIndividualStatusHistBucket(
    328                 "Sequence Mixed AP/Aware: rttToAware.histogramIndividualStatus[0]",
    329                 log.rttToAware.histogramIndividualStatus[0], WifiMetricsProto.WifiRttLog.SUCCESS,
    330                 4);
    331         validateProtoIndividualStatusHistBucket(
    332                 "Sequence Mixed AP/Aware: rttToAware.histogramIndividualStatus[1]",
    333                 log.rttToAware.histogramIndividualStatus[1],
    334                 WifiMetricsProto.WifiRttLog.MISSING_RESULT, 1);
    335 
    336         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramDistance[0]",
    337                 log.rttToAware.histogramDistance[0], 60 * 1000, 100 * 1000, 1);
    338         validateProtoHistBucket("Sequence Mixed AP/Aware: rttToAware.histogramDistance[1]",
    339                 log.rttToAware.histogramDistance[1], 100 * 1000, Integer.MAX_VALUE, 3);
    340     }
    341 
    342     /**
    343      * Verify the behavior when the HAL returns with NULL array.
    344      */
    345     @Test
    346     public void testRecordNullArrayResults() {
    347         WifiMetricsProto.WifiRttLog log;
    348 
    349         mDut.clear();
    350         RangingRequest requestMixed25 = getDummyRangingRequest(2, 5);
    351         mDut.recordResult(requestMixed25, null);
    352 
    353         log = mDut.consolidateProto();
    354 
    355         checkMainStats("Sequence Mixed AP/Aware", log, 0, 0);
    356 
    357         checkPeerStats("Sequence Mixed AP/Aware: AP", log.rttToAp, 0, 0, 0, 0, 0, 1, 0, 0);
    358 
    359         validateProtoIndividualStatusHistBucket(
    360                 "Sequence Mixed AP/Aware: rttToAp.histogramIndividualStatus[1]",
    361                 log.rttToAp.histogramIndividualStatus[0],
    362                 WifiMetricsProto.WifiRttLog.MISSING_RESULT, 2);
    363 
    364         checkPeerStats("Sequence Mixed AP/Aware: Aware", log.rttToAware, 0, 0, 0, 0, 0, 1, 0, 0);
    365 
    366         validateProtoIndividualStatusHistBucket(
    367                 "Sequence Mixed AP/Aware: rttToAware.histogramIndividualStatus[0]",
    368                 log.rttToAware.histogramIndividualStatus[0],
    369                 WifiMetricsProto.WifiRttLog.MISSING_RESULT, 5);
    370     }
    371 
    372     /**
    373      * Verify that all individual status codes are translated correctly.
    374      */
    375     @Test
    376     public void testRecordResultsStatuses() {
    377         WifiMetricsProto.WifiRttLog log;
    378 
    379         mDut.clear();
    380 
    381         recordResultNTimes(RttStatus.SUCCESS, 5);
    382         recordResultNTimes(RttStatus.FAILURE, 6);
    383         recordResultNTimes(RttStatus.FAIL_NO_RSP, 7);
    384         recordResultNTimes(RttStatus.FAIL_REJECTED, 8);
    385         recordResultNTimes(RttStatus.FAIL_NOT_SCHEDULED_YET, 9);
    386         recordResultNTimes(RttStatus.FAIL_TM_TIMEOUT, 10);
    387         recordResultNTimes(RttStatus.FAIL_AP_ON_DIFF_CHANNEL, 11);
    388         recordResultNTimes(RttStatus.FAIL_NO_CAPABILITY, 12);
    389         recordResultNTimes(RttStatus.ABORTED, 13);
    390         recordResultNTimes(RttStatus.FAIL_INVALID_TS, 14);
    391         recordResultNTimes(RttStatus.FAIL_PROTOCOL, 15);
    392         recordResultNTimes(RttStatus.FAIL_SCHEDULE, 16);
    393         recordResultNTimes(RttStatus.FAIL_BUSY_TRY_LATER, 17);
    394         recordResultNTimes(RttStatus.INVALID_REQ, 18);
    395         recordResultNTimes(RttStatus.NO_WIFI, 19);
    396         recordResultNTimes(RttStatus.FAIL_FTM_PARAM_OVERRIDE, 20);
    397 
    398         log = mDut.consolidateProto();
    399 
    400         collector.checkThat("AP histogramIndividualStatus.length",
    401                 log.rttToAp.histogramIndividualStatus.length, equalTo(16));
    402 
    403         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[0]",
    404                 log.rttToAp.histogramIndividualStatus[0], WifiMetricsProto.WifiRttLog.SUCCESS, 5);
    405         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[1]",
    406                 log.rttToAp.histogramIndividualStatus[1], WifiMetricsProto.WifiRttLog.FAILURE, 6);
    407         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[2]",
    408                 log.rttToAp.histogramIndividualStatus[2], WifiMetricsProto.WifiRttLog.FAIL_NO_RSP,
    409                 7);
    410         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[3]",
    411                 log.rttToAp.histogramIndividualStatus[3], WifiMetricsProto.WifiRttLog.FAIL_REJECTED,
    412                 8);
    413         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[4]",
    414                 log.rttToAp.histogramIndividualStatus[4],
    415                 WifiMetricsProto.WifiRttLog.FAIL_NOT_SCHEDULED_YET, 9);
    416         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[5]",
    417                 log.rttToAp.histogramIndividualStatus[5],
    418                 WifiMetricsProto.WifiRttLog.FAIL_TM_TIMEOUT, 10);
    419         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[6]",
    420                 log.rttToAp.histogramIndividualStatus[6],
    421                 WifiMetricsProto.WifiRttLog.FAIL_AP_ON_DIFF_CHANNEL, 11);
    422         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[7]",
    423                 log.rttToAp.histogramIndividualStatus[7],
    424                 WifiMetricsProto.WifiRttLog.FAIL_NO_CAPABILITY, 12);
    425         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[8]",
    426                 log.rttToAp.histogramIndividualStatus[8], WifiMetricsProto.WifiRttLog.ABORTED, 13);
    427         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[9]",
    428                 log.rttToAp.histogramIndividualStatus[9],
    429                 WifiMetricsProto.WifiRttLog.FAIL_INVALID_TS, 14);
    430         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[10]",
    431                 log.rttToAp.histogramIndividualStatus[10],
    432                 WifiMetricsProto.WifiRttLog.FAIL_PROTOCOL, 15);
    433         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[11]",
    434                 log.rttToAp.histogramIndividualStatus[11],
    435                 WifiMetricsProto.WifiRttLog.FAIL_SCHEDULE, 16);
    436         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[12]",
    437                 log.rttToAp.histogramIndividualStatus[12],
    438                 WifiMetricsProto.WifiRttLog.FAIL_BUSY_TRY_LATER, 17);
    439         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[13]",
    440                 log.rttToAp.histogramIndividualStatus[13], WifiMetricsProto.WifiRttLog.INVALID_REQ,
    441                 18);
    442         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[14]",
    443                 log.rttToAp.histogramIndividualStatus[14], WifiMetricsProto.WifiRttLog.NO_WIFI, 19);
    444         validateProtoIndividualStatusHistBucket("rttToAp.histogramIndividualStatus[15]",
    445                 log.rttToAp.histogramIndividualStatus[15],
    446                 WifiMetricsProto.WifiRttLog.FAIL_FTM_PARAM_OVERRIDE, 20);
    447 
    448         collector.checkThat("Aware histogramIndividualStatus.length",
    449                 log.rttToAware.histogramIndividualStatus.length, equalTo(0));
    450     }
    451 
    452     /**
    453      * Verify that all overall status codes are recorded correctly.
    454      */
    455     @Test
    456     public void testRecordOverallStatus() {
    457         WifiMetricsProto.WifiRttLog log;
    458 
    459         mDut.clear();
    460 
    461         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_SUCCESS, 5);
    462         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_FAIL, 6);
    463         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_RTT_NOT_AVAILABLE, 7);
    464         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_TIMEOUT, 8);
    465         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_THROTTLE, 9);
    466         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_HAL_FAILURE, 10);
    467         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_AWARE_TRANSLATION_FAILURE,
    468                 11);
    469         recordOverallStatusNTimes(WifiMetricsProto.WifiRttLog.OVERALL_LOCATION_PERMISSION_MISSING,
    470                 12);
    471 
    472         log = mDut.consolidateProto();
    473 
    474         collector.checkThat("histogramOverallStatus.length", log.histogramOverallStatus.length,
    475                 equalTo(8));
    476 
    477         validateProtoOverallStatusHistBucket("histogramOverallStatus[0]",
    478                 log.histogramOverallStatus[0], WifiMetricsProto.WifiRttLog.OVERALL_SUCCESS, 5);
    479         validateProtoOverallStatusHistBucket("histogramOverallStatus[1]",
    480                 log.histogramOverallStatus[1], WifiMetricsProto.WifiRttLog.OVERALL_FAIL, 6);
    481         validateProtoOverallStatusHistBucket("histogramOverallStatus[2]",
    482                 log.histogramOverallStatus[2],
    483                 WifiMetricsProto.WifiRttLog.OVERALL_RTT_NOT_AVAILABLE, 7);
    484         validateProtoOverallStatusHistBucket("histogramOverallStatus[3]",
    485                 log.histogramOverallStatus[3], WifiMetricsProto.WifiRttLog.OVERALL_TIMEOUT, 8);
    486         validateProtoOverallStatusHistBucket("histogramOverallStatus[4]",
    487                 log.histogramOverallStatus[4], WifiMetricsProto.WifiRttLog.OVERALL_THROTTLE, 9);
    488         validateProtoOverallStatusHistBucket("histogramOverallStatus[5]",
    489                 log.histogramOverallStatus[5], WifiMetricsProto.WifiRttLog.OVERALL_HAL_FAILURE, 10);
    490         validateProtoOverallStatusHistBucket("histogramOverallStatus[6]",
    491                 log.histogramOverallStatus[6],
    492                 WifiMetricsProto.WifiRttLog.OVERALL_AWARE_TRANSLATION_FAILURE, 11);
    493         validateProtoOverallStatusHistBucket("histogramOverallStatus[7]",
    494                 log.histogramOverallStatus[7],
    495                 WifiMetricsProto.WifiRttLog.OVERALL_LOCATION_PERMISSION_MISSING, 12);
    496     }
    497 
    498     // Utilities
    499 
    500     /**
    501      * Mock the elapsed time since boot to the input argument.
    502      */
    503     private void setTime(long timeMs) {
    504         when(mClock.getElapsedSinceBootMillis()).thenReturn(timeMs);
    505     }
    506 
    507     private void validateProtoHistBucket(String logPrefix,
    508             WifiMetricsProto.WifiRttLog.HistogramBucket bucket, long start, long end, int count) {
    509         collector.checkThat(logPrefix + ": start", bucket.start, equalTo(start));
    510         collector.checkThat(logPrefix + ": end", bucket.end, equalTo(end));
    511         collector.checkThat(logPrefix + ": count", bucket.count, equalTo(count));
    512     }
    513 
    514     private void validateProtoOverallStatusHistBucket(String logPrefix,
    515             WifiMetricsProto.WifiRttLog.RttOverallStatusHistogramBucket bucket, int status,
    516             int count) {
    517         collector.checkThat(logPrefix + ": statusType", bucket.statusType, equalTo(status));
    518         collector.checkThat(logPrefix + ": count", bucket.count, equalTo(count));
    519     }
    520 
    521     private void validateProtoIndividualStatusHistBucket(String logPrefix,
    522             WifiMetricsProto.WifiRttLog.RttIndividualStatusHistogramBucket bucket, int status,
    523             int count) {
    524         collector.checkThat(logPrefix + ": statusType", bucket.statusType, equalTo(status));
    525         collector.checkThat(logPrefix + ": count", bucket.count, equalTo(count));
    526     }
    527 
    528     private void checkMainStats(String msgPrefix, WifiMetricsProto.WifiRttLog log, int numRequests,
    529             int histogramOverallStatusLength) {
    530         collector.checkThat(msgPrefix + ": numRequests", log.numRequests, equalTo(numRequests));
    531         collector.checkThat(msgPrefix + ": histogramOverallStatus.length",
    532                 log.histogramOverallStatus.length,
    533                 equalTo(histogramOverallStatusLength));
    534     }
    535 
    536     private void checkPeerStats(String msgPrefix, WifiMetricsProto.WifiRttLog.RttToPeerLog log,
    537             int numRequests, int numIndividualRequests,
    538             int numApps, int histogramNumRequestsPerAppLength,
    539             int histogramNumPeersPerRequestLength, int histogramIndividualStatusLength,
    540             int histogramDistanceLength, int histogramRequestIntervalMsLength) {
    541         collector.checkThat(msgPrefix + ": numRequests", log.numRequests, equalTo(numRequests));
    542         collector.checkThat(msgPrefix + ": numIndividualRequests", log.numIndividualRequests,
    543                 equalTo(numIndividualRequests));
    544         collector.checkThat(msgPrefix + ": numApps", log.numApps, equalTo(numApps));
    545         collector.checkThat(msgPrefix + ": histogramNumRequestsPerApp.length",
    546                 log.histogramNumRequestsPerApp.length, equalTo(histogramNumRequestsPerAppLength));
    547         collector.checkThat(msgPrefix + ": histogramNumPeersPerRequest.length",
    548                 log.histogramNumPeersPerRequest.length, equalTo(histogramNumPeersPerRequestLength));
    549         collector.checkThat(msgPrefix + ": histogramIndividualStatus.length",
    550                 log.histogramIndividualStatus.length, equalTo(histogramIndividualStatusLength));
    551         collector.checkThat(msgPrefix + ": histogramDistance.length",
    552                 log.histogramDistance.length, equalTo(histogramDistanceLength));
    553         collector.checkThat(msgPrefix + ": histogramRequestIntervalMs.length",
    554                 log.histogramRequestIntervalMs.length, equalTo(histogramRequestIntervalMsLength));
    555     }
    556 
    557     private RangingRequest getDummyRangingRequest(int countAp, int countAware) {
    558         RangingRequest.Builder builder = new RangingRequest.Builder();
    559         byte[] dummyMacBase = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5};
    560 
    561         for (int i = 0; i < countAp; ++i) {
    562             dummyMacBase[0]++;
    563             builder.addResponder(new ResponderConfig(MacAddress.fromBytes(dummyMacBase),
    564                     ResponderConfig.RESPONDER_AP, true, 0, 0, 0, 0, 0));
    565         }
    566         for (int i = 0; i < countAware; ++i) {
    567             dummyMacBase[0]++;
    568             builder.addResponder(new ResponderConfig(MacAddress.fromBytes(dummyMacBase),
    569                     ResponderConfig.RESPONDER_AWARE, true, 0, 0, 0, 0, 0));
    570         }
    571 
    572         return builder.build();
    573     }
    574 
    575     private List<RttResult> getDummyRangingResults(RangingRequest request, double baseDistanceM,
    576             double incrDistanceM) {
    577         List<RttResult> halResults = new ArrayList<>();
    578         double distance = baseDistanceM;
    579 
    580         for (ResponderConfig peer : request.mRttPeers) {
    581             RttResult rttResult = new RttResult();
    582             rttResult.status = RttStatus.SUCCESS;
    583             System.arraycopy(peer.macAddress.toByteArray(), 0, rttResult.addr, 0, 6);
    584             rttResult.distanceInMm = (int) (distance * 1000);
    585             distance += incrDistanceM;
    586             halResults.add(rttResult);
    587         }
    588 
    589         return halResults;
    590     }
    591 
    592     private void recordResultNTimes(int status, int n) {
    593         RangingRequest request = getDummyRangingRequest(1, 0);
    594         List<RttResult> results = getDummyRangingResults(request, 0, 0);
    595         RttResult result = results.get(0);
    596         result.status = status;
    597 
    598         for (int i = 0; i < n; ++i) {
    599             mDut.recordResult(request, results);
    600         }
    601     }
    602 
    603     private void recordOverallStatusNTimes(int status, int n) {
    604         for (int i = 0; i < n; ++i) {
    605             mDut.recordOverallStatus(status);
    606         }
    607     }
    608 
    609     private void dumpDut(String prefix) {
    610         StringWriter sw = new StringWriter();
    611         mDut.dump(null, new PrintWriter(sw), null);
    612         Log.e("RttMetrics", prefix + sw.toString());
    613     }
    614 }
    615