1 /*
2  * Copyright (C) 2024 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.car.cts;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.junit.Assert.assertThrows;
22 import static org.junit.Assume.assumeFalse;
23 import static org.junit.Assume.assumeTrue;
24 
25 import android.car.feature.Flags;
26 import android.platform.test.annotations.RequiresFlagsEnabled;
27 import android.platform.test.flag.junit.CheckFlagsRule;
28 import android.platform.test.flag.junit.host.HostFlagsValueProvider;
29 
30 import com.android.car.wifi.CarWifiDumpProto;
31 import com.android.compatibility.common.util.ApiTest;
32 import com.android.compatibility.common.util.PollingCheck;
33 import com.android.compatibility.common.util.ProtoUtils;
34 import com.android.tradefed.invoker.TestInformation;
35 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
36 import com.android.tradefed.testtype.junit4.AfterClassWithInfo;
37 import com.android.tradefed.testtype.junit4.BeforeClassWithInfo;
38 
39 import org.junit.Rule;
40 import org.junit.Test;
41 import org.junit.runner.RunWith;
42 
43 import java.util.concurrent.TimeUnit;
44 
45 @RunWith(DeviceJUnit4ClassRunner.class)
46 public final class CarWifiHostTest extends CarHostJUnit4TestCase {
47     private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(15);
48 
49     private static final String GET_PERSISTENT_TETHERING =
50             "settings get global android.car.ENABLE_PERSISTENT_TETHERING";
51     private static final String ENABLE_PERSISTENT_TETHERING =
52             "settings put global android.car.ENABLE_PERSISTENT_TETHERING true";
53     private static final String DISABLE_PERSISTENT_TETHERING =
54             "settings put global android.car.ENABLE_PERSISTENT_TETHERING false";
55     private static final String CMD_DUMPSYS_WIFI =
56             "dumpsys car_service --services CarWifiService";
57     private static final String CMD_DUMPSYS_WIFI_PROTO =
58             "dumpsys car_service --services CarWifiService --proto";
59     private static final String WIFI_HOTSPOT_ON = "cmd wifi start-softap CarWifiService open";
60     private static final String WIFI_HOTSPOT_OFF = "cmd wifi stop-softap";
61     private static boolean sTetheringStatusBefore;
62     private static boolean sTetheringPersistingBefore;
63 
64     @Rule
65     public final CheckFlagsRule mCheckFlagsRule =
66             HostFlagsValueProvider.createCheckFlagsRule(this::getDevice);
67 
68     /**
69      * Prepares the device to restore back to original state post-test.
70      *
71      * @param testInfo Test Information
72      * @throws Exception if connection with device is lost and cannot be recovered.
73      */
74     @BeforeClassWithInfo
beforeClassWithDevice(TestInformation testInfo)75     public static void beforeClassWithDevice(TestInformation testInfo) throws Exception {
76         // TODO: b/324961709 - Re-factor to use proto dump
77         sTetheringStatusBefore = testInfo.getDevice().executeShellCommand(CMD_DUMPSYS_WIFI)
78                 .contains("Tethering enabled: true");
79         sTetheringPersistingBefore = testInfo.getDevice().executeShellCommand(
80                 GET_PERSISTENT_TETHERING).contains("true");
81     }
82 
83     /**
84      * Restores original state to conditions before testing.
85      *
86      * @param testInfo Test Information
87      * @throws Exception if connection with device is lost and cannot be recovered.
88      */
89     @AfterClassWithInfo
afterClassWithInfo(TestInformation testInfo)90     public static void afterClassWithInfo(TestInformation testInfo) throws Exception {
91         String hotspotCommand = (sTetheringStatusBefore ? WIFI_HOTSPOT_ON : WIFI_HOTSPOT_OFF);
92         testInfo.getDevice().executeShellCommand(hotspotCommand);
93 
94         String persistTetheringCommand =
95                 (sTetheringPersistingBefore ? ENABLE_PERSISTENT_TETHERING
96                         : DISABLE_PERSISTENT_TETHERING);
97         testInfo.getDevice().executeShellCommand(persistTetheringCommand);
98     }
99 
100     @Test
101     @RequiresFlagsEnabled({Flags.FLAG_PERSIST_AP_SETTINGS, Flags.FLAG_CAR_DUMP_TO_PROTO})
102     @ApiTest(apis = {"android.car.settings.CarSettings#ENABLE_PERSISTENT_TETHERING"})
testPersistTetheringCarSetting_enablingWithCapability_autoShutdownDisabled()103     public void testPersistTetheringCarSetting_enablingWithCapability_autoShutdownDisabled()
104             throws Exception {
105         assumeTrue("Skipping test: tethering capability disabled",
106                 isPersistTetheringCapabilityEnabled());
107         executeCommand(ENABLE_PERSISTENT_TETHERING);
108         assertThat(isAutoShutdownEnabled()).isFalse();
109     }
110 
111     @Test
112     @RequiresFlagsEnabled({Flags.FLAG_PERSIST_AP_SETTINGS, Flags.FLAG_CAR_DUMP_TO_PROTO})
113     @ApiTest(apis = {"android.car.settings.CarSettings#ENABLE_PERSISTENT_TETHERING"})
testPersistTetheringCarSetting_disablingWithCapability_autoShutdownEnabled()114     public void testPersistTetheringCarSetting_disablingWithCapability_autoShutdownEnabled()
115             throws Exception {
116         assumeTrue("Skipping test: tethering capability disabled",
117                 isPersistTetheringCapabilityEnabled());
118         executeCommand(DISABLE_PERSISTENT_TETHERING);
119         assertThat(isAutoShutdownEnabled()).isTrue();
120     }
121 
122     @Test
123     @RequiresFlagsEnabled({Flags.FLAG_PERSIST_AP_SETTINGS, Flags.FLAG_CAR_DUMP_TO_PROTO})
124     @ApiTest(apis = {"android.car.settings.CarSettings#ENABLE_PERSISTENT_TETHERING"})
testPersistTetheringCarSetting_enablingNoCapability_autoShutdownUnchanged()125     public void testPersistTetheringCarSetting_enablingNoCapability_autoShutdownUnchanged()
126             throws Exception {
127         assumeFalse("Skipping test: tethering capability enabled",
128                 isPersistTetheringCapabilityEnabled());
129         boolean autoShutdownEnabledBefore = isAutoShutdownEnabled();
130         executeCommand(ENABLE_PERSISTENT_TETHERING);
131         assertThat(isAutoShutdownEnabled()).isEqualTo(autoShutdownEnabledBefore);
132     }
133 
134     @Test
135     @RequiresFlagsEnabled({Flags.FLAG_PERSIST_AP_SETTINGS, Flags.FLAG_CAR_DUMP_TO_PROTO})
136     @ApiTest(apis = {"android.car.settings.CarSettings#ENABLE_PERSISTENT_TETHERING"})
testPersistTetheringCarSetting_disablingNoCapability_autoShutdownUnchanged()137     public void testPersistTetheringCarSetting_disablingNoCapability_autoShutdownUnchanged()
138             throws Exception {
139         assumeFalse("Skipping test: tethering capability enabled",
140                 isPersistTetheringCapabilityEnabled());
141         boolean autoShutdownEnabledBefore = isAutoShutdownEnabled();
142         executeCommand(DISABLE_PERSISTENT_TETHERING);
143         assertThat(isAutoShutdownEnabled()).isEqualTo(autoShutdownEnabledBefore);
144     }
145 
146     @Test
147     @RequiresFlagsEnabled({Flags.FLAG_PERSIST_AP_SETTINGS, Flags.FLAG_CAR_DUMP_TO_PROTO})
148     @ApiTest(apis = {"android.car.settings.CarSettings#ENABLE_PERSISTENT_TETHERING"})
testPersistTetheringCarSetting_withCapabilityTetheringEnabled_tetheringOnReboot()149     public void testPersistTetheringCarSetting_withCapabilityTetheringEnabled_tetheringOnReboot()
150             throws Exception {
151         assumeTrue("Skipping test: tethering capability disabled",
152                 isPersistTetheringCapabilityEnabled());
153 
154         enablePersistTetheringAndReboot(/* enableTethering= */ true);
155 
156         PollingCheck.check("Tethering NOT enabled", TIMEOUT_MS, this::isTetheringEnabled);
157         assertThat(isAutoShutdownEnabled()).isFalse();
158     }
159 
160     @Test
161     @RequiresFlagsEnabled({Flags.FLAG_PERSIST_AP_SETTINGS, Flags.FLAG_CAR_DUMP_TO_PROTO})
162     @ApiTest(apis = {"android.car.settings.CarSettings#ENABLE_PERSISTENT_TETHERING"})
testPersistTetheringCarSetting_withCapabilityTetheringDisabled_noTetheringOnReboot()163     public void testPersistTetheringCarSetting_withCapabilityTetheringDisabled_noTetheringOnReboot()
164             throws Exception {
165         assumeTrue("Skipping test: tethering capability disabled",
166                 isPersistTetheringCapabilityEnabled());
167 
168         enablePersistTetheringAndReboot(/* enableTethering= */ false);
169 
170         assertThrows(AssertionError.class,
171                 () -> PollingCheck.check("Tethering NOT enabled", TIMEOUT_MS,
172                         this::isTetheringEnabled));
173     }
174 
175     @Test
176     @RequiresFlagsEnabled({Flags.FLAG_PERSIST_AP_SETTINGS, Flags.FLAG_CAR_DUMP_TO_PROTO})
177     @ApiTest(apis = {"android.car.settings.CarSettings#ENABLE_PERSISTENT_TETHERING"})
testPersistTetheringCarSetting_noCapabilityTetheringEnabled_noTetheringOnReboot()178     public void testPersistTetheringCarSetting_noCapabilityTetheringEnabled_noTetheringOnReboot()
179             throws Exception {
180         assumeFalse("Skipping test: tethering capability enabled",
181                 isPersistTetheringCapabilityEnabled());
182 
183         enablePersistTetheringAndReboot(/* enableTethering= */ true);
184 
185         assertThrows(AssertionError.class,
186                 () -> PollingCheck.check("Tethering NOT enabled", TIMEOUT_MS,
187                         this::isTetheringEnabled));
188     }
189 
isTetheringEnabled()190     private boolean isTetheringEnabled() throws Exception {
191         CarWifiDumpProto carWifiDump = ProtoUtils.getProto(getDevice(),
192                 CarWifiDumpProto.parser(), CMD_DUMPSYS_WIFI_PROTO);
193         return carWifiDump.getTetheringEnabled();
194     }
195 
isAutoShutdownEnabled()196     private boolean isAutoShutdownEnabled() throws Exception {
197         CarWifiDumpProto carWifiDump = ProtoUtils.getProto(getDevice(),
198                 CarWifiDumpProto.parser(), CMD_DUMPSYS_WIFI_PROTO);
199         return carWifiDump.getAutoShutdownEnabled();
200     }
201 
isPersistTetheringCapabilityEnabled()202     private boolean isPersistTetheringCapabilityEnabled() throws Exception {
203         CarWifiDumpProto carWifiDump = ProtoUtils.getProto(getDevice(),
204                 CarWifiDumpProto.parser(), CMD_DUMPSYS_WIFI_PROTO);
205         return carWifiDump.getPersistTetheringCapabilitiesEnabled();
206     }
207 
enablePersistTetheringAndReboot(boolean enableTethering)208     private void enablePersistTetheringAndReboot(boolean enableTethering) throws Exception {
209         String hotspotCommand = (enableTethering ? WIFI_HOTSPOT_ON : WIFI_HOTSPOT_OFF);
210         executeCommand(hotspotCommand);
211 
212         executeCommand(ENABLE_PERSISTENT_TETHERING);
213 
214         reboot();
215         waitForCarServiceReady();
216         waitForUserInitialized(/* userId= */ 0);
217     }
218 }
219