1 /* 2 * Copyright (C) 2020 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 package com.android.compatibility.targetprep; 17 18 import static com.google.common.truth.Truth.assertThat; 19 20 import static org.testng.Assert.assertThrows; 21 22 import com.android.ddmlib.Log; 23 import com.android.ddmlib.Log.ILogOutput; 24 import com.android.ddmlib.Log.LogLevel; 25 import com.android.tradefed.build.BuildInfo; 26 import com.android.tradefed.config.OptionSetter; 27 import com.android.tradefed.device.ITestDevice; 28 import com.android.tradefed.invoker.IInvocationContext; 29 import com.android.tradefed.invoker.InvocationContext; 30 import com.android.tradefed.invoker.TestInformation; 31 import com.android.tradefed.targetprep.TargetSetupError; 32 import com.android.tradefed.util.CommandResult; 33 import com.android.tradefed.util.CommandStatus; 34 35 import com.google.common.truth.Correspondence; 36 37 import org.junit.After; 38 import org.junit.Before; 39 import org.junit.Test; 40 import org.junit.runner.RunWith; 41 import org.junit.runners.JUnit4; 42 import org.mockito.Mockito; 43 44 import java.util.ArrayList; 45 46 @RunWith(JUnit4.class) 47 public final class CheckGmsPreparerTest { 48 private CheckGmsPreparer mPreparer; 49 private LogCaptor mLogCaptor; 50 51 @Before setUp()52 public void setUp() throws Exception { 53 mPreparer = new CheckGmsPreparer(); 54 new OptionSetter(mPreparer).setOptionValue(CheckGmsPreparer.OPTION_ENABLE, "true"); 55 56 mLogCaptor = new LogCaptor(); 57 Log.addLogger(mLogCaptor); 58 } 59 60 @After tearDown()61 public void tearDown() { 62 Log.removeLogger(mLogCaptor); 63 } 64 65 @Test setUp_checkDisabledAndGmsAbsent_doesNotReboot()66 public void setUp_checkDisabledAndGmsAbsent_doesNotReboot() throws Exception { 67 ITestDevice device = createDeviceWithGmsAbsent(); 68 disablePreparer(mPreparer); 69 70 mPreparer.setUp(createTestInfo(device)); 71 72 Mockito.verify(device, Mockito.never()).reboot(); 73 assertThat(mLogCaptor.getLogItems()) 74 .comparingElementsUsing(createContainsErrorLogCorrespondence()) 75 .doesNotContain("GMS"); 76 } 77 78 @Test tearDown_checkDisabledAndGmsAbsent_doesNotLog()79 public void tearDown_checkDisabledAndGmsAbsent_doesNotLog() throws Exception { 80 ITestDevice device = createDeviceWithGmsAbsent(); 81 disablePreparer(mPreparer); 82 83 mPreparer.tearDown(createTestInfo(device), null); 84 85 assertThat(mLogCaptor.getLogItems()) 86 .comparingElementsUsing(createContainsErrorLogCorrespondence()) 87 .doesNotContain("GMS"); 88 } 89 90 @Test tearDown_setUpThrows_doesNotCheck()91 public void tearDown_setUpThrows_doesNotCheck() throws Exception { 92 ITestDevice device = createDeviceWithGmsAbsent(); 93 TestInformation testInfo = createTestInfo(device); 94 assertThrows(TargetSetupError.class, () -> mPreparer.setUp(testInfo)); 95 mLogCaptor.reset(); 96 Mockito.reset(device); 97 Mockito.when(device.executeShellV2Command(Mockito.any())) 98 .thenReturn(createFailedCommandResult()); 99 100 mPreparer.tearDown(testInfo, null); 101 102 Mockito.verify(device, Mockito.never()).executeShellV2Command(Mockito.any()); 103 } 104 105 @Test tearDown_setUpRecoveredGms_checksGms()106 public void tearDown_setUpRecoveredGms_checksGms() throws Exception { 107 ITestDevice device = createDeviceWithGmsAbsentAndRecoverable(); 108 TestInformation testInfo = createTestInfo(device); 109 mPreparer.setUp(testInfo); 110 mLogCaptor.reset(); 111 Mockito.reset(device); 112 Mockito.when(device.executeShellV2Command(CheckGmsPreparer.CHECK_GMS_COMMAND)) 113 .thenReturn(createSuccessfulCommandResult()); 114 115 mPreparer.tearDown(testInfo, null); 116 117 Mockito.verify(device, Mockito.atLeast(1)) 118 .executeShellV2Command(CheckGmsPreparer.CHECK_GMS_COMMAND); 119 } 120 121 @Test tearDown_setUpFoundGms_checksGms()122 public void tearDown_setUpFoundGms_checksGms() throws Exception { 123 ITestDevice device = createDeviceWithGmsPresent(); 124 TestInformation testInfo = createTestInfo(device); 125 mPreparer.setUp(testInfo); 126 Mockito.reset(device); 127 mLogCaptor.reset(); 128 Mockito.when(device.executeShellV2Command(CheckGmsPreparer.CHECK_GMS_COMMAND)) 129 .thenReturn(createSuccessfulCommandResult()); 130 131 mPreparer.tearDown(testInfo, null); 132 133 Mockito.verify(device, Mockito.atLeast(1)) 134 .executeShellV2Command(CheckGmsPreparer.CHECK_GMS_COMMAND); 135 } 136 137 @Test setUp_gmsPresent_doesNotReboot()138 public void setUp_gmsPresent_doesNotReboot() throws Exception { 139 ITestDevice device = createDeviceWithGmsPresent(); 140 141 mPreparer.setUp(createTestInfo(device)); 142 143 Mockito.verify(device, Mockito.never()).reboot(); 144 assertThat(mLogCaptor.getLogItems()) 145 .comparingElementsUsing(createContainsErrorLogCorrespondence()) 146 .doesNotContain("GMS"); 147 } 148 149 @Test setUp_gmsProcessRecoveredAfterReboot_doesNotThrow()150 public void setUp_gmsProcessRecoveredAfterReboot_doesNotThrow() throws Exception { 151 ITestDevice device = createDeviceWithGmsAbsentAndRecoverable(); 152 153 mPreparer.setUp(createTestInfo(device)); 154 155 Mockito.verify(device, Mockito.times(1)).reboot(); 156 assertThat(mLogCaptor.getLogItems()) 157 .comparingElementsUsing(createContainsErrorLogCorrespondence()) 158 .contains("GMS"); 159 } 160 161 @Test setUp_gmsProcessNotRecoveredAfterReboot_throwsException()162 public void setUp_gmsProcessNotRecoveredAfterReboot_throwsException() throws Exception { 163 ITestDevice device = createDeviceWithGmsAbsent(); 164 165 assertThrows(TargetSetupError.class, () -> mPreparer.setUp(createTestInfo(device))); 166 Mockito.verify(device, Mockito.times(1)).reboot(); 167 assertThat(mLogCaptor.getLogItems()) 168 .comparingElementsUsing(createContainsErrorLogCorrespondence()) 169 .contains("GMS"); 170 } 171 172 @Test tearDown_gmsProcessPresent_doesNotLog()173 public void tearDown_gmsProcessPresent_doesNotLog() throws Exception { 174 ITestDevice device = createDeviceWithGmsPresent(); 175 176 mPreparer.tearDown(createTestInfo(device), null); 177 178 assertThat(mLogCaptor.getLogItems()) 179 .comparingElementsUsing(createContainsErrorLogCorrespondence()) 180 .doesNotContain("GMS"); 181 } 182 183 @Test tearDown_gmsProcessAbsent_logsError()184 public void tearDown_gmsProcessAbsent_logsError() throws Exception { 185 ITestDevice device = createDeviceWithGmsAbsent(); 186 187 mPreparer.tearDown(createTestInfo(device), null); 188 189 assertThat(mLogCaptor.getLogItems()) 190 .comparingElementsUsing(createContainsErrorLogCorrespondence()) 191 .contains("GMS"); 192 } 193 disablePreparer(CheckGmsPreparer preparer)194 private static void disablePreparer(CheckGmsPreparer preparer) throws Exception { 195 new OptionSetter(preparer).setOptionValue(CheckGmsPreparer.OPTION_ENABLE, "false"); 196 } 197 createContainsErrorLogCorrespondence()198 private static Correspondence<LogItem, String> createContainsErrorLogCorrespondence() { 199 return Correspondence.from( 200 (LogItem actual, String expected) -> { 201 return actual.getLogLevel() == LogLevel.ERROR 202 && actual.getMessage().contains(expected); 203 }, 204 "has an error log that contains"); 205 } 206 createDeviceWithGmsAbsentAndRecoverable()207 private static ITestDevice createDeviceWithGmsAbsentAndRecoverable() throws Exception { 208 ITestDevice device = Mockito.mock(ITestDevice.class); 209 Mockito.doReturn(createFailedCommandResult()) 210 .doReturn(createSuccessfulCommandResult()) 211 .when(device) 212 .executeShellV2Command(CheckGmsPreparer.CHECK_GMS_COMMAND); 213 return device; 214 } 215 createDeviceWithGmsPresent()216 private static ITestDevice createDeviceWithGmsPresent() throws Exception { 217 ITestDevice device = Mockito.mock(ITestDevice.class); 218 Mockito.when(device.executeShellV2Command(CheckGmsPreparer.CHECK_GMS_COMMAND)) 219 .thenReturn(createSuccessfulCommandResult()); 220 return device; 221 } 222 createDeviceWithGmsAbsent()223 private static ITestDevice createDeviceWithGmsAbsent() throws Exception { 224 ITestDevice device = Mockito.mock(ITestDevice.class); 225 Mockito.when(device.executeShellV2Command(CheckGmsPreparer.CHECK_GMS_COMMAND)) 226 .thenReturn(createFailedCommandResult()); 227 return device; 228 } 229 230 private static final class LogCaptor implements ILogOutput { 231 private ArrayList<LogItem> mLogItems = new ArrayList<>(); 232 reset()233 void reset() { 234 mLogItems.clear(); 235 } 236 getLogItems()237 ArrayList<LogItem> getLogItems() { 238 return mLogItems; 239 } 240 241 @Override printLog(LogLevel logLevel, String tag, String message)242 public void printLog(LogLevel logLevel, String tag, String message) { 243 mLogItems.add(new LogItem(logLevel, tag, message)); 244 } 245 246 @Override printAndPromptLog(LogLevel logLevel, String tag, String message)247 public void printAndPromptLog(LogLevel logLevel, String tag, String message) { 248 printLog(logLevel, tag, message); 249 } 250 } 251 252 private static final class LogItem { 253 private LogLevel mLogLevel; 254 private String mMessage; 255 getLogLevel()256 LogLevel getLogLevel() { 257 return mLogLevel; 258 } 259 getMessage()260 String getMessage() { 261 return mMessage; 262 } 263 LogItem(LogLevel logLevel, @SuppressWarnings("unused") String tag, String message)264 LogItem(LogLevel logLevel, @SuppressWarnings("unused") String tag, String message) { 265 mLogLevel = logLevel; 266 mMessage = message; 267 } 268 } 269 createTestInfo(ITestDevice device)270 private static TestInformation createTestInfo(ITestDevice device) { 271 IInvocationContext context = new InvocationContext(); 272 context.addAllocatedDevice("device1", device); 273 context.addDeviceBuildInfo("device1", new BuildInfo()); 274 return TestInformation.newBuilder().setInvocationContext(context).build(); 275 } 276 createSuccessfulCommandResult()277 private static CommandResult createSuccessfulCommandResult() { 278 CommandResult commandResult = new CommandResult(CommandStatus.SUCCESS); 279 commandResult.setExitCode(0); 280 return commandResult; 281 } 282 createFailedCommandResult()283 private static CommandResult createFailedCommandResult() { 284 CommandResult commandResult = new CommandResult(CommandStatus.FAILED); 285 commandResult.setExitCode(1); 286 return commandResult; 287 } 288 } 289