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.DeviceConfigKeys.NAMESPACE_SYSTEM_TIME;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 import static com.google.common.truth.Truth.assertWithMessage;
23 
24 import android.app.time.cts.shell.DeviceConfigShellHelper;
25 import android.app.time.cts.shell.DeviceShellCommandExecutor;
26 import android.app.time.cts.shell.LocationShellHelper;
27 import android.app.time.cts.shell.host.HostShellCommandExecutor;
28 import android.app.time.cts.shell.TimeZoneDetectorShellHelper;
29 import android.cts.statsdatom.lib.AtomTestUtils;
30 import android.cts.statsdatom.lib.ConfigUtils;
31 import android.cts.statsdatom.lib.DeviceUtils;
32 import android.cts.statsdatom.lib.ReportUtils;
33 
34 import com.android.os.AtomsProto;
35 import com.android.os.AtomsProto.TimeZoneDetectorState.DetectionMode;
36 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
37 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
38 
39 import org.junit.After;
40 import org.junit.Before;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 
44 import java.util.List;
45 
46 /** Host-side CTS tests for the time zone detector service stats logging. */
47 @RunWith(DeviceJUnit4ClassRunner.class)
48 public class TimeZoneDetectorStatsTest extends BaseHostJUnit4Test {
49 
50     private TimeZoneDetectorShellHelper mTimeZoneDetectorShellHelper;
51     private LocationShellHelper mLocationShellHelper;
52     private DeviceConfigShellHelper mDeviceConfigShellHelper;
53     private DeviceConfigShellHelper.PreTestState mDeviceConfigPreTestState;
54 
55     @Before
setUp()56     public void setUp() throws Exception {
57         DeviceShellCommandExecutor shellCommandExecutor = new HostShellCommandExecutor(getDevice());
58         mTimeZoneDetectorShellHelper = new TimeZoneDetectorShellHelper(shellCommandExecutor);
59         mLocationShellHelper = new LocationShellHelper(shellCommandExecutor);
60         mDeviceConfigShellHelper = new DeviceConfigShellHelper(shellCommandExecutor);
61         mDeviceConfigPreTestState = mDeviceConfigShellHelper.setSyncModeForTest(
62                 DeviceConfigShellHelper.SYNC_DISABLED_MODE_UNTIL_REBOOT, NAMESPACE_SYSTEM_TIME);
63 
64         ConfigUtils.removeConfig(getDevice());
65         ReportUtils.clearReports(getDevice());
66     }
67 
68     @After
tearDown()69     public void tearDown() throws Exception {
70         ConfigUtils.removeConfig(getDevice());
71         ReportUtils.clearReports(getDevice());
72         mDeviceConfigShellHelper.restoreDeviceConfigStateForTest(mDeviceConfigPreTestState);
73     }
74 
75     @Test
testAtom_TimeZoneDetectorState()76     public void testAtom_TimeZoneDetectorState() throws Exception {
77         // Enable the atom.
78         ConfigUtils.uploadConfigForPulledAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
79                 AtomsProto.Atom.TIME_ZONE_DETECTOR_STATE_FIELD_NUMBER);
80         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
81 
82         // This should trigger a pull.
83         AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice());
84         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
85 
86         // Extract and assert about TimeZoneDetectorState.
87         List<AtomsProto.Atom> atoms = ReportUtils.getGaugeMetricAtoms(getDevice());
88 
89         boolean found = false;
90         for (AtomsProto.Atom atom : atoms) {
91             if (atom.hasTimeZoneDetectorState()) {
92                 AtomsProto.TimeZoneDetectorState state = atom.getTimeZoneDetectorState();
93 
94                 // There are a few parts of the pull metric we can check easily via the command
95                 // line. Checking more would require adding more commands or something that dumps a
96                 // proto. This test provides at least some coverage that the atom is working /
97                 // matches actual state.
98 
99                 // The shell reports the same info the atom does for geo detection supported.
100                 boolean geoDetectionSupportedFromShell =
101                         mTimeZoneDetectorShellHelper.isGeoDetectionSupported();
102                 assertThat(state.getGeoSupported()).isEqualTo(geoDetectionSupportedFromShell);
103 
104                 // The shell reports the same info the atom does for location enabled.
105                 boolean locationEnabledForCurrentUserFromShell =
106                         mLocationShellHelper.isLocationEnabledForCurrentUser();
107                 assertThat(state.getLocationEnabled())
108                         .isEqualTo(locationEnabledForCurrentUserFromShell);
109 
110                 // The shell reports the user's setting for auto detection.
111                 boolean autoDetectionEnabledFromShell =
112                         mTimeZoneDetectorShellHelper.isAutoDetectionEnabled();
113                 assertThat(state.getAutoDetectionSetting())
114                         .isEqualTo(autoDetectionEnabledFromShell);
115 
116                 boolean telephonyDetectionSupportedFromShell =
117                         mTimeZoneDetectorShellHelper.isTelephonyDetectionSupported();
118                 boolean noAutoDetectionSupported =
119                         !(telephonyDetectionSupportedFromShell || geoDetectionSupportedFromShell);
120                 // The atom reports the functional state for "detection mode", which is derived from
121                 // device config and settings. This logic basically repeats the logic used on the
122                 // device.
123                 DetectionMode expectedDetectionMode;
124                 if (noAutoDetectionSupported || !autoDetectionEnabledFromShell) {
125                     expectedDetectionMode = DetectionMode.MANUAL;
126                 } else {
127                     boolean geoDetectionSettingEnabledFromShell =
128                             mTimeZoneDetectorShellHelper.isGeoDetectionEnabled();
129                     boolean expectedGeoDetectionEnabled =
130                             geoDetectionSupportedFromShell
131                                     && locationEnabledForCurrentUserFromShell
132                                     && geoDetectionSettingEnabledFromShell;
133                     if (expectedGeoDetectionEnabled) {
134                         expectedDetectionMode = DetectionMode.GEO;
135                     } else {
136                         expectedDetectionMode = DetectionMode.TELEPHONY;
137                     }
138                 }
139                 assertThat(state.getDetectionMode()).isEqualTo(expectedDetectionMode);
140 
141                 found = true;
142                 break;
143             }
144         }
145         assertWithMessage("Did not find a matching atom TimeZoneDetectorState")
146                 .that(found).isTrue();
147     }
148 }
149