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 156 @Test setUp_gmsProcessNotRecoveredAfterReboot_throwsException()157 public void setUp_gmsProcessNotRecoveredAfterReboot_throwsException() throws Exception { 158 ITestDevice device = createDeviceWithGmsAbsent(); 159 160 assertThrows(TargetSetupError.class, () -> mPreparer.setUp(createTestInfo(device))); 161 } 162 163 @Test tearDown_gmsProcessPresent_doesNotLog()164 public void tearDown_gmsProcessPresent_doesNotLog() throws Exception { 165 ITestDevice device = createDeviceWithGmsPresent(); 166 167 mPreparer.tearDown(createTestInfo(device), null); 168 169 assertThat(mLogCaptor.getLogItems()) 170 .comparingElementsUsing(createContainsErrorLogCorrespondence()) 171 .doesNotContain("GMS"); 172 } 173 disablePreparer(CheckGmsPreparer preparer)174 private static void disablePreparer(CheckGmsPreparer preparer) throws Exception { 175 new OptionSetter(preparer).setOptionValue(CheckGmsPreparer.OPTION_ENABLE, "false"); 176 } 177 createContainsErrorLogCorrespondence()178 private static Correspondence<LogItem, String> createContainsErrorLogCorrespondence() { 179 return Correspondence.from( 180 (LogItem actual, String expected) -> { 181 return actual.getLogLevel() == LogLevel.ERROR 182 && actual.getMessage().contains(expected); 183 }, 184 "has an error log that contains"); 185 } 186 createDeviceWithGmsAbsentAndRecoverable()187 private static ITestDevice createDeviceWithGmsAbsentAndRecoverable() throws Exception { 188 ITestDevice device = Mockito.mock(ITestDevice.class); 189 Mockito.doReturn(createFailedCommandResult()) 190 .doReturn(createSuccessfulCommandResult()) 191 .when(device) 192 .executeShellV2Command(CheckGmsPreparer.CHECK_GMS_COMMAND); 193 return device; 194 } 195 createDeviceWithGmsPresent()196 private static ITestDevice createDeviceWithGmsPresent() throws Exception { 197 ITestDevice device = Mockito.mock(ITestDevice.class); 198 Mockito.when(device.executeShellV2Command(CheckGmsPreparer.CHECK_GMS_COMMAND)) 199 .thenReturn(createSuccessfulCommandResult()); 200 return device; 201 } 202 createDeviceWithGmsAbsent()203 private static ITestDevice createDeviceWithGmsAbsent() throws Exception { 204 ITestDevice device = Mockito.mock(ITestDevice.class); 205 Mockito.when(device.executeShellV2Command(CheckGmsPreparer.CHECK_GMS_COMMAND)) 206 .thenReturn(createFailedCommandResult()); 207 return device; 208 } 209 210 private static final class LogCaptor implements ILogOutput { 211 private ArrayList<LogItem> mLogItems = new ArrayList<>(); 212 reset()213 void reset() { 214 mLogItems.clear(); 215 } 216 getLogItems()217 ArrayList<LogItem> getLogItems() { 218 return mLogItems; 219 } 220 221 @Override printLog(LogLevel logLevel, String tag, String message)222 public void printLog(LogLevel logLevel, String tag, String message) { 223 mLogItems.add(new LogItem(logLevel, tag, message)); 224 } 225 226 @Override printAndPromptLog(LogLevel logLevel, String tag, String message)227 public void printAndPromptLog(LogLevel logLevel, String tag, String message) { 228 printLog(logLevel, tag, message); 229 } 230 } 231 232 private static final class LogItem { 233 private LogLevel mLogLevel; 234 private String mMessage; 235 getLogLevel()236 LogLevel getLogLevel() { 237 return mLogLevel; 238 } 239 getMessage()240 String getMessage() { 241 return mMessage; 242 } 243 LogItem(LogLevel logLevel, @SuppressWarnings("unused") String tag, String message)244 LogItem(LogLevel logLevel, @SuppressWarnings("unused") String tag, String message) { 245 mLogLevel = logLevel; 246 mMessage = message; 247 } 248 } 249 createTestInfo(ITestDevice device)250 private static TestInformation createTestInfo(ITestDevice device) { 251 IInvocationContext context = new InvocationContext(); 252 context.addAllocatedDevice("device1", device); 253 context.addDeviceBuildInfo("device1", new BuildInfo()); 254 return TestInformation.newBuilder().setInvocationContext(context).build(); 255 } 256 createSuccessfulCommandResult()257 private static CommandResult createSuccessfulCommandResult() { 258 CommandResult commandResult = new CommandResult(CommandStatus.SUCCESS); 259 commandResult.setExitCode(0); 260 return commandResult; 261 } 262 createFailedCommandResult()263 private static CommandResult createFailedCommandResult() { 264 CommandResult commandResult = new CommandResult(CommandStatus.FAILED); 265 commandResult.setExitCode(1); 266 return commandResult; 267 } 268 } 269 270