1 /*
2  * Copyright (C) 2021 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.time.cts.host;
18 
19 import static android.app.time.cts.shell.LocationTimeZoneManagerShellHelper.PRIMARY_PROVIDER_INDEX;
20 import static android.app.time.cts.shell.LocationTimeZoneManagerShellHelper.PROVIDER_MODE_DISABLED;
21 import static android.app.time.cts.shell.LocationTimeZoneManagerShellHelper.PROVIDER_MODE_SIMULATED;
22 import static android.app.time.cts.shell.LocationTimeZoneManagerShellHelper.SECONDARY_PROVIDER_INDEX;
23 
24 import static java.util.stream.Collectors.toList;
25 
26 import android.cts.statsdatom.lib.AtomTestUtils;
27 import android.cts.statsdatom.lib.ConfigUtils;
28 import android.cts.statsdatom.lib.DeviceUtils;
29 import android.cts.statsdatom.lib.ReportUtils;
30 
31 import com.android.os.AtomsProto;
32 import com.android.os.AtomsProto.LocationTimeZoneProviderStateChanged;
33 import com.android.os.StatsLog;
34 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
35 
36 import org.junit.After;
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 
41 import java.util.Arrays;
42 import java.util.Collections;
43 import java.util.List;
44 import java.util.Set;
45 import java.util.function.Function;
46 
47 /** Host-side CTS tests for the location time zone manager service stats logging. */
48 @RunWith(DeviceJUnit4ClassRunner.class)
49 public class LocationTimeZoneManagerStatsTest extends BaseLocationTimeZoneManagerHostTest {
50 
51     private static final int PROVIDER_STATES_COUNT =
52             LocationTimeZoneProviderStateChanged.State.values().length;
53 
54     @Before
55     @Override
setUp()56     public void setUp() throws Exception {
57         super.setUp();
58         ConfigUtils.removeConfig(getDevice());
59         ReportUtils.clearReports(getDevice());
60     }
61 
62     @After
63     @Override
tearDown()64     public void tearDown() throws Exception {
65         ConfigUtils.removeConfig(getDevice());
66         ReportUtils.clearReports(getDevice());
67         super.tearDown();
68     }
69 
70     @Test
testAtom_locationTimeZoneProviderStateChanged()71     public void testAtom_locationTimeZoneProviderStateChanged() throws Exception {
72         setProviderModeOverride(PRIMARY_PROVIDER_INDEX, PROVIDER_MODE_DISABLED);
73         setProviderModeOverride(SECONDARY_PROVIDER_INDEX, PROVIDER_MODE_SIMULATED);
74         mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(false);
75 
76         startLocationTimeZoneManagerService();
77 
78         ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
79                 AtomsProto.Atom.LOCATION_TIME_ZONE_PROVIDER_STATE_CHANGED_FIELD_NUMBER);
80 
81         // Turn geo detection on and off, twice.
82         for (int i = 0; i < 2; i++) {
83             mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(true);
84             Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT);
85             mTimeZoneDetectorShellHelper.setGeoDetectionEnabled(false);
86             Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT);
87         }
88 
89         // Sorted list of events in order in which they occurred.
90         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
91 
92         // States.
93         Set<Integer> primaryProviderStarted = singletonStateId(PRIMARY_PROVIDER_INDEX,
94                 LocationTimeZoneProviderStateChanged.State.INITIALIZING);
95         Set<Integer> primaryProviderFailed = singletonStateId(PRIMARY_PROVIDER_INDEX,
96                 LocationTimeZoneProviderStateChanged.State.PERM_FAILED);
97         Set<Integer> secondaryProviderStarted = singletonStateId(SECONDARY_PROVIDER_INDEX,
98                 LocationTimeZoneProviderStateChanged.State.INITIALIZING);
99         Set<Integer> secondaryProviderStopped = singletonStateId(SECONDARY_PROVIDER_INDEX,
100                 LocationTimeZoneProviderStateChanged.State.STOPPED);
101         Function<AtomsProto.Atom, Integer> eventToStateFunction = atom -> {
102             int providerIndex = atom.getLocationTimeZoneProviderStateChanged().getProviderIndex();
103             return stateId(providerIndex,
104                     atom.getLocationTimeZoneProviderStateChanged().getState());
105         };
106 
107         // Add state sets to the list in order.
108         // Assert that the events happened in the expected order. This does not check "wait" (the
109         // time between events).
110         List<Set<Integer>> stateSets = Arrays.asList(
111                 primaryProviderStarted, primaryProviderFailed,
112                 secondaryProviderStarted, secondaryProviderStopped,
113                 secondaryProviderStarted, secondaryProviderStopped);
114         AtomTestUtils.assertStatesOccurred(stateSets, data,
115                 0 /* wait */, eventToStateFunction);
116 
117         // Assert that the events for the secondary provider happened in the expected order. This
118         // does check "wait" (the time between events).
119         List<StatsLog.EventMetricData> secondaryEvents =
120                 extractEventsForProviderIndex(data, SECONDARY_PROVIDER_INDEX);
121         List<Set<Integer>> secondaryStateSets = Arrays.asList(
122                 secondaryProviderStarted, secondaryProviderStopped,
123                 secondaryProviderStarted, secondaryProviderStopped);
124         AtomTestUtils.assertStatesOccurred(secondaryStateSets, secondaryEvents,
125                 AtomTestUtils.WAIT_TIME_SHORT /* wait */, eventToStateFunction);
126     }
127 
singletonStateId(int providerIndex, LocationTimeZoneProviderStateChanged.State state)128     private static Set<Integer> singletonStateId(int providerIndex,
129             LocationTimeZoneProviderStateChanged.State state) {
130         return Collections.singleton(stateId(providerIndex, state));
131     }
132 
extractEventsForProviderIndex( List<StatsLog.EventMetricData> data, int providerIndex)133     private static List<StatsLog.EventMetricData> extractEventsForProviderIndex(
134             List<StatsLog.EventMetricData> data, int providerIndex) {
135         return data.stream().filter(event -> {
136             if (!event.getAtom().hasLocationTimeZoneProviderStateChanged()) {
137                 return false;
138             }
139             return event.getAtom().getLocationTimeZoneProviderStateChanged().getProviderIndex()
140                     == providerIndex;
141         }).collect(toList());
142     }
143 
144     /** Maps a (provider index, provider state) pair to an integer state ID. */
145     private static Integer stateId(
146             int providerIndex, LocationTimeZoneProviderStateChanged.State providerState) {
147         return (providerIndex * PROVIDER_STATES_COUNT) + providerState.getNumber();
148     }
149 }
150