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