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 package com.android.csuite.core; 17 18 import static com.google.common.truth.Truth.assertThat; 19 20 import static org.junit.Assert.assertThrows; 21 import static org.mockito.Mockito.when; 22 23 import android.service.dropbox.DropBoxManagerServiceDumpProto; 24 25 import com.android.csuite.core.DeviceUtils.DeviceTimestamp; 26 import com.android.csuite.core.DeviceUtils.DeviceUtilsException; 27 import com.android.csuite.core.DeviceUtils.DropboxEntry; 28 import com.android.tradefed.device.DeviceRuntimeException; 29 import com.android.tradefed.device.ITestDevice; 30 import com.android.tradefed.util.CommandResult; 31 import com.android.tradefed.util.CommandStatus; 32 import com.android.tradefed.util.IRunUtil; 33 34 import com.google.common.jimfs.Jimfs; 35 import com.google.protobuf.ByteString; 36 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 import org.junit.runners.JUnit4; 40 import org.mockito.ArgumentMatcher; 41 import org.mockito.Mockito; 42 43 import java.io.IOException; 44 import java.nio.file.FileSystem; 45 import java.nio.file.Files; 46 import java.nio.file.Path; 47 import java.util.Arrays; 48 import java.util.List; 49 import java.util.Set; 50 import java.util.concurrent.atomic.AtomicBoolean; 51 52 @RunWith(JUnit4.class) 53 public final class DeviceUtilsTest { 54 private ITestDevice mDevice = Mockito.mock(ITestDevice.class); 55 private IRunUtil mRunUtil = Mockito.mock(IRunUtil.class); 56 private final FileSystem mFileSystem = 57 Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix()); 58 59 @Test launchPackage_packageDoesNotExist_returnsFalse()60 public void launchPackage_packageDoesNotExist_returnsFalse() throws Exception { 61 when(mDevice.executeShellV2Command(Mockito.startsWith("monkey -p"))) 62 .thenReturn(createFailedCommandResult()); 63 DeviceUtils sut = createSubjectUnderTest(); 64 65 assertThrows(DeviceUtilsException.class, () -> sut.launchPackage("package.name")); 66 } 67 68 @Test launchPackage_successfullyLaunchedThePackage_returnsTrue()69 public void launchPackage_successfullyLaunchedThePackage_returnsTrue() throws Exception { 70 when(mDevice.executeShellV2Command(Mockito.startsWith("monkey -p"))) 71 .thenReturn(createSuccessfulCommandResultWithStdout("")); 72 DeviceUtils sut = createSubjectUnderTest(); 73 74 sut.launchPackage("package.name"); 75 } 76 77 @Test currentTimeMillis_deviceCommandFailed_throwsException()78 public void currentTimeMillis_deviceCommandFailed_throwsException() throws Exception { 79 DeviceUtils sut = createSubjectUnderTest(); 80 when(mDevice.executeShellV2Command(Mockito.startsWith("echo"))) 81 .thenReturn(createFailedCommandResult()); 82 83 assertThrows(DeviceRuntimeException.class, () -> sut.currentTimeMillis()); 84 } 85 86 @Test currentTimeMillis_unexpectedFormat_throwsException()87 public void currentTimeMillis_unexpectedFormat_throwsException() throws Exception { 88 DeviceUtils sut = createSubjectUnderTest(); 89 when(mDevice.executeShellV2Command(Mockito.startsWith("echo"))) 90 .thenReturn(createSuccessfulCommandResultWithStdout("")); 91 92 assertThrows(DeviceRuntimeException.class, () -> sut.currentTimeMillis()); 93 } 94 95 @Test currentTimeMillis_successful_returnsTime()96 public void currentTimeMillis_successful_returnsTime() throws Exception { 97 DeviceUtils sut = createSubjectUnderTest(); 98 when(mDevice.executeShellV2Command(Mockito.startsWith("echo"))) 99 .thenReturn(createSuccessfulCommandResultWithStdout("123")); 100 101 DeviceTimestamp result = sut.currentTimeMillis(); 102 103 assertThat(result.get()).isEqualTo(Long.parseLong("123")); 104 } 105 106 @Test runWithScreenRecording_recordingDidNotStart_jobIsExecuted()107 public void runWithScreenRecording_recordingDidNotStart_jobIsExecuted() throws Exception { 108 DeviceUtils sut = createSubjectUnderTest(); 109 when(mRunUtil.runCmdInBackground(Mockito.argThat(contains("shell", "screenrecord")))) 110 .thenReturn(Mockito.mock(Process.class)); 111 when(mDevice.executeShellV2Command(Mockito.startsWith("ls"))) 112 .thenReturn(createFailedCommandResult()); 113 AtomicBoolean executed = new AtomicBoolean(false); 114 DeviceUtils.RunnableThrowingDeviceNotAvailable job = () -> executed.set(true); 115 116 sut.runWithScreenRecording(job, video -> {}); 117 118 assertThat(executed.get()).isTrue(); 119 } 120 121 @Test runWithScreenRecording_recordCommandThrowsException_jobIsExecuted()122 public void runWithScreenRecording_recordCommandThrowsException_jobIsExecuted() 123 throws Exception { 124 when(mRunUtil.runCmdInBackground(Mockito.argThat(contains("shell", "screenrecord")))) 125 .thenThrow(new IOException()); 126 DeviceUtils sut = createSubjectUnderTest(); 127 AtomicBoolean executed = new AtomicBoolean(false); 128 DeviceUtils.RunnableThrowingDeviceNotAvailable job = () -> executed.set(true); 129 130 sut.runWithScreenRecording(job, video -> {}); 131 132 assertThat(executed.get()).isTrue(); 133 } 134 135 @Test runWithScreenRecording_jobThrowsException_videoFileIsHandled()136 public void runWithScreenRecording_jobThrowsException_videoFileIsHandled() throws Exception { 137 when(mRunUtil.runCmdInBackground(Mockito.argThat(contains("shell", "screenrecord")))) 138 .thenReturn(Mockito.mock(Process.class)); 139 when(mDevice.executeShellV2Command(Mockito.startsWith("ls"))) 140 .thenReturn(createSuccessfulCommandResultWithStdout("")); 141 DeviceUtils sut = createSubjectUnderTest(); 142 DeviceUtils.RunnableThrowingDeviceNotAvailable job = 143 () -> { 144 throw new RuntimeException(); 145 }; 146 AtomicBoolean handled = new AtomicBoolean(false); 147 148 assertThrows( 149 RuntimeException.class, 150 () -> sut.runWithScreenRecording(job, video -> handled.set(true))); 151 152 assertThat(handled.get()).isTrue(); 153 } 154 155 @Test getPackageVersionName_deviceCommandFailed_returnsUnknown()156 public void getPackageVersionName_deviceCommandFailed_returnsUnknown() throws Exception { 157 DeviceUtils sut = createSubjectUnderTest(); 158 when(mDevice.executeShellV2Command(Mockito.endsWith("grep versionName"))) 159 .thenReturn(createFailedCommandResult()); 160 161 String result = sut.getPackageVersionName("any"); 162 163 assertThat(result).isEqualTo(DeviceUtils.UNKNOWN); 164 } 165 166 @Test getPackageVersionName_deviceCommandReturnsUnexpected_returnsUnknown()167 public void getPackageVersionName_deviceCommandReturnsUnexpected_returnsUnknown() 168 throws Exception { 169 DeviceUtils sut = createSubjectUnderTest(); 170 when(mDevice.executeShellV2Command(Mockito.endsWith("grep versionName"))) 171 .thenReturn( 172 createSuccessfulCommandResultWithStdout( 173 "unexpected " + DeviceUtils.VERSION_NAME_PREFIX)); 174 175 String result = sut.getPackageVersionName("any"); 176 177 assertThat(result).isEqualTo(DeviceUtils.UNKNOWN); 178 } 179 180 @Test getPackageVersionName_deviceCommandSucceed_returnsVersionName()181 public void getPackageVersionName_deviceCommandSucceed_returnsVersionName() throws Exception { 182 DeviceUtils sut = createSubjectUnderTest(); 183 when(mDevice.executeShellV2Command(Mockito.endsWith("grep versionName"))) 184 .thenReturn( 185 createSuccessfulCommandResultWithStdout( 186 " " + DeviceUtils.VERSION_NAME_PREFIX + "123")); 187 188 String result = sut.getPackageVersionName("any"); 189 190 assertThat(result).isEqualTo("123"); 191 } 192 193 @Test getPackageVersionCode_deviceCommandFailed_returnsUnknown()194 public void getPackageVersionCode_deviceCommandFailed_returnsUnknown() throws Exception { 195 DeviceUtils sut = createSubjectUnderTest(); 196 when(mDevice.executeShellV2Command(Mockito.endsWith("grep versionCode"))) 197 .thenReturn(createFailedCommandResult()); 198 199 String result = sut.getPackageVersionCode("any"); 200 201 assertThat(result).isEqualTo(DeviceUtils.UNKNOWN); 202 } 203 204 @Test getPackageVersionCode_deviceCommandReturnsUnexpected_returnsUnknown()205 public void getPackageVersionCode_deviceCommandReturnsUnexpected_returnsUnknown() 206 throws Exception { 207 DeviceUtils sut = createSubjectUnderTest(); 208 when(mDevice.executeShellV2Command(Mockito.endsWith("grep versionCode"))) 209 .thenReturn( 210 createSuccessfulCommandResultWithStdout( 211 "unexpected " + DeviceUtils.VERSION_CODE_PREFIX)); 212 213 String result = sut.getPackageVersionCode("any"); 214 215 assertThat(result).isEqualTo(DeviceUtils.UNKNOWN); 216 } 217 218 @Test getPackageVersionCode_deviceCommandSucceed_returnVersionCode()219 public void getPackageVersionCode_deviceCommandSucceed_returnVersionCode() throws Exception { 220 DeviceUtils sut = createSubjectUnderTest(); 221 when(mDevice.executeShellV2Command(Mockito.endsWith("grep versionCode"))) 222 .thenReturn( 223 createSuccessfulCommandResultWithStdout( 224 " " + DeviceUtils.VERSION_CODE_PREFIX + "123")); 225 226 String result = sut.getPackageVersionCode("any"); 227 228 assertThat(result).isEqualTo("123"); 229 } 230 231 @Test getDropboxEntries_noEntries_returnsEmptyList()232 public void getDropboxEntries_noEntries_returnsEmptyList() throws Exception { 233 DeviceUtils sut = createSubjectUnderTest(); 234 when(mRunUtil.runTimedCmd( 235 Mockito.anyLong(), 236 Mockito.eq("sh"), 237 Mockito.eq("-c"), 238 Mockito.contains("dumpsys dropbox"))) 239 .thenReturn(createSuccessfulCommandResultWithStdout("")); 240 241 List<DropboxEntry> result = sut.getDropboxEntries(Set.of("")); 242 243 assertThat(result).isEmpty(); 244 } 245 246 @Test getDropboxEntries_entryExists_returnsEntry()247 public void getDropboxEntries_entryExists_returnsEntry() throws Exception { 248 Path dumpFile = Files.createTempFile(mFileSystem.getPath("/"), "test", ".tmp"); 249 long time = 123; 250 String data = "abc"; 251 String tag = "tag"; 252 DropBoxManagerServiceDumpProto proto = 253 DropBoxManagerServiceDumpProto.newBuilder() 254 .addEntries( 255 DropBoxManagerServiceDumpProto.Entry.newBuilder() 256 .setTimeMs(time) 257 .setData(ByteString.copyFromUtf8(data))) 258 .build(); 259 Files.write(dumpFile, proto.toByteArray()); 260 DeviceUtils sut = createSubjectUnderTestWithTempFile(dumpFile); 261 when(mRunUtil.runTimedCmd( 262 Mockito.anyLong(), Mockito.eq("sh"), Mockito.eq("-c"), Mockito.anyString())) 263 .thenReturn(createSuccessfulCommandResultWithStdout("")); 264 265 List<DropboxEntry> result = sut.getDropboxEntries(Set.of(tag)); 266 267 assertThat(result.get(0).getTime()).isEqualTo(time); 268 assertThat(result.get(0).getData()).isEqualTo(data); 269 assertThat(result.get(0).getTag()).isEqualTo(tag); 270 } 271 createSubjectUnderTestWithTempFile(Path tempFile)272 private DeviceUtils createSubjectUnderTestWithTempFile(Path tempFile) { 273 when(mDevice.getSerialNumber()).thenReturn("SERIAL"); 274 FakeClock fakeClock = new FakeClock(); 275 return new DeviceUtils( 276 mDevice, fakeClock.getSleeper(), fakeClock, () -> mRunUtil, () -> tempFile); 277 } 278 createSubjectUnderTest()279 private DeviceUtils createSubjectUnderTest() { 280 when(mDevice.getSerialNumber()).thenReturn("SERIAL"); 281 FakeClock fakeClock = new FakeClock(); 282 return new DeviceUtils( 283 mDevice, 284 fakeClock.getSleeper(), 285 fakeClock, 286 () -> mRunUtil, 287 () -> Files.createTempFile(mFileSystem.getPath("/"), "test", ".tmp")); 288 } 289 290 private static class FakeClock implements DeviceUtils.Clock { 291 private long mCurrentTime = System.currentTimeMillis(); 292 private DeviceUtils.Sleeper mSleeper = duration -> mCurrentTime += duration; 293 getSleeper()294 private DeviceUtils.Sleeper getSleeper() { 295 return mSleeper; 296 } 297 298 @Override currentTimeMillis()299 public long currentTimeMillis() { 300 return mCurrentTime += 1; 301 } 302 } 303 contains(String... args)304 private static ArgumentMatcher<String[]> contains(String... args) { 305 return array -> Arrays.asList(array).containsAll(Arrays.asList(args)); 306 } 307 createSuccessfulCommandResultWithStdout(String stdout)308 private static CommandResult createSuccessfulCommandResultWithStdout(String stdout) { 309 CommandResult commandResult = new CommandResult(CommandStatus.SUCCESS); 310 commandResult.setExitCode(0); 311 commandResult.setStdout(stdout); 312 commandResult.setStderr(""); 313 return commandResult; 314 } 315 createFailedCommandResult()316 private static CommandResult createFailedCommandResult() { 317 CommandResult commandResult = new CommandResult(CommandStatus.FAILED); 318 commandResult.setExitCode(1); 319 commandResult.setStdout(""); 320 commandResult.setStderr("error"); 321 return commandResult; 322 } 323 } 324