| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.tradefed.device; |
| |
| import com.android.ddmlib.AdbCommandRejectedException; |
| import com.android.ddmlib.IDevice; |
| import com.android.ddmlib.IShellOutputReceiver; |
| import com.android.ddmlib.ShellCommandUnresponsiveException; |
| import com.android.ddmlib.TimeoutException; |
| import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner; |
| import com.android.ddmlib.testrunner.ITestRunListener; |
| import com.android.tradefed.device.ITestDevice.MountPointInfo; |
| import com.android.tradefed.device.ITestDevice.RecoveryMode; |
| import com.android.tradefed.log.LogUtil.CLog; |
| import com.android.tradefed.result.InputStreamSource; |
| import com.android.tradefed.util.ArrayUtil; |
| import com.android.tradefed.util.CommandResult; |
| import com.android.tradefed.util.CommandStatus; |
| import com.android.tradefed.util.IRunUtil; |
| import com.android.tradefed.util.StreamUtil; |
| |
| import junit.framework.TestCase; |
| |
| import org.easymock.EasyMock; |
| import org.easymock.IAnswer; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Set; |
| |
| /** |
| * Unit tests for {@link TestDevice}. |
| */ |
| public class TestDeviceTest extends TestCase { |
| |
| private IDevice mMockIDevice; |
| private IShellOutputReceiver mMockReceiver; |
| private TestDevice mTestDevice; |
| private TestDevice mRecoveryTestDevice; |
| private TestDevice mNoFastbootTestDevice; |
| private IDeviceRecovery mMockRecovery; |
| private IDeviceStateMonitor mMockMonitor; |
| private IRunUtil mMockRunUtil; |
| private IWifiHelper mMockWifi; |
| |
| /** |
| * A {@link TestDevice} that is suitable for running tests against |
| */ |
| private class TestableTestDevice extends TestDevice { |
| public TestableTestDevice() { |
| super(mMockIDevice, mMockMonitor); |
| } |
| |
| @Override |
| public void postBootSetup() { |
| // too annoying to mock out postBootSetup actions everyone, so do nothing |
| } |
| |
| @Override |
| IRunUtil getRunUtil() { |
| return mMockRunUtil; |
| } |
| |
| @Override |
| void doReboot() throws DeviceNotAvailableException, UnsupportedOperationException { |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| mMockIDevice = EasyMock.createMock(IDevice.class); |
| EasyMock.expect(mMockIDevice.getSerialNumber()).andReturn("serial").anyTimes(); |
| mMockReceiver = EasyMock.createMock(IShellOutputReceiver.class); |
| mMockRecovery = EasyMock.createMock(IDeviceRecovery.class); |
| mMockMonitor = EasyMock.createMock(IDeviceStateMonitor.class); |
| mMockRunUtil = EasyMock.createMock(IRunUtil.class); |
| mMockWifi = EasyMock.createMock(IWifiHelper.class); |
| |
| // A TestDevice with a no-op recoverDevice() implementation |
| mTestDevice = new TestableTestDevice() { |
| @Override |
| public void recoverDevice() throws DeviceNotAvailableException { |
| // ignore |
| } |
| |
| @Override |
| IWifiHelper createWifiHelper() { |
| return mMockWifi; |
| } |
| }; |
| mTestDevice.setRecovery(mMockRecovery); |
| mTestDevice.setCommandTimeout(100); |
| mTestDevice.setLogStartDelay(-1); |
| |
| // TestDevice with intact recoverDevice() |
| mRecoveryTestDevice = new TestableTestDevice(); |
| mRecoveryTestDevice.setRecovery(mMockRecovery); |
| mRecoveryTestDevice.setCommandTimeout(100); |
| mRecoveryTestDevice.setLogStartDelay(-1); |
| |
| // TestDevice without fastboot |
| mNoFastbootTestDevice = new TestableTestDevice(); |
| mNoFastbootTestDevice.setFastbootEnabled(false); |
| mNoFastbootTestDevice.setRecovery(mMockRecovery); |
| mNoFastbootTestDevice.setCommandTimeout(100); |
| mNoFastbootTestDevice.setLogStartDelay(-1); |
| } |
| |
| /** |
| * Test {@link TestDevice#enableAdbRoot()} when adb is already root |
| */ |
| public void testEnableAdbRoot_alreadyRoot() throws Exception { |
| injectShellResponse("id", "uid=0(root) gid=0(root)"); |
| EasyMock.replay(mMockIDevice); |
| assertTrue(mTestDevice.enableAdbRoot()); |
| } |
| |
| /** |
| * Test {@link TestDevice#enableAdbRoot()} when adb is not root |
| */ |
| public void testEnableAdbRoot_notRoot() throws Exception { |
| setEnableAdbRootExpectations(); |
| EasyMock.replay(mMockIDevice, mMockRunUtil, mMockMonitor); |
| assertTrue(mTestDevice.enableAdbRoot()); |
| } |
| |
| /** |
| * Configure EasyMock expectations for a successful adb root call |
| */ |
| private void setEnableAdbRootExpectations() throws Exception { |
| injectShellResponse("id", "uid=2000(shell) gid=2000(shell)"); |
| injectShellResponse("id", "uid=0(root) gid=0(root)"); |
| CommandResult adbResult = new CommandResult(); |
| adbResult.setStatus(CommandStatus.SUCCESS); |
| adbResult.setStdout("restarting adbd as root"); |
| EasyMock.expect( |
| mMockRunUtil.runTimedCmd(EasyMock.anyLong(), EasyMock.eq("adb"), |
| EasyMock.eq("-s"), EasyMock.eq("serial"), EasyMock.eq("root"))).andReturn( |
| adbResult); |
| EasyMock.expect(mMockMonitor.waitForDeviceNotAvailable(EasyMock.anyLong())).andReturn( |
| Boolean.TRUE); |
| EasyMock.expect(mMockMonitor.waitForDeviceOnline()).andReturn( |
| mMockIDevice); |
| } |
| |
| /** |
| * Test that {@link TestDevice#enableAdbRoot()} reattempts adb root |
| */ |
| public void testEnableAdbRoot_rootRetry() throws Exception { |
| injectShellResponse("id", "uid=2000(shell) gid=2000(shell)"); |
| injectShellResponse("id", "uid=2000(shell) gid=2000(shell)"); |
| injectShellResponse("id", "uid=0(root) gid=0(root)"); |
| CommandResult adbBadResult = new CommandResult(CommandStatus.SUCCESS); |
| adbBadResult.setStdout(""); |
| EasyMock.expect( |
| mMockRunUtil.runTimedCmd(EasyMock.anyLong(), EasyMock.eq("adb"), |
| EasyMock.eq("-s"), EasyMock.eq("serial"), EasyMock.eq("root"))).andReturn( |
| adbBadResult); |
| CommandResult adbResult = new CommandResult(CommandStatus.SUCCESS); |
| adbResult.setStdout("restarting adbd as root"); |
| EasyMock.expect( |
| mMockRunUtil.runTimedCmd(EasyMock.anyLong(), EasyMock.eq("adb"), |
| EasyMock.eq("-s"), EasyMock.eq("serial"), EasyMock.eq("root"))).andReturn( |
| adbResult); |
| EasyMock.expect(mMockMonitor.waitForDeviceNotAvailable(EasyMock.anyLong())).andReturn( |
| Boolean.TRUE).times(2); |
| EasyMock.expect(mMockMonitor.waitForDeviceOnline()).andReturn( |
| mMockIDevice).times(2); |
| EasyMock.replay(mMockIDevice, mMockRunUtil, mMockMonitor); |
| assertTrue(mTestDevice.enableAdbRoot()); |
| } |
| |
| /** |
| * Test that {@link TestDevice#isAdbRoot()} for device without adb root. |
| */ |
| public void testIsAdbRootForNonRoot() throws Exception { |
| injectShellResponse("id", "uid=2000(shell) gid=2000(shell)"); |
| EasyMock.replay(mMockIDevice); |
| assertFalse(mTestDevice.isAdbRoot()); |
| } |
| |
| /** |
| * Test that {@link TestDevice#isAdbRoot()} for device with adb root. |
| */ |
| public void testIsAdbRootForRoot() throws Exception { |
| injectShellResponse("id", "uid=0(root) gid=0(root)"); |
| EasyMock.replay(mMockIDevice); |
| assertTrue(mTestDevice.isAdbRoot()); |
| } |
| |
| /** |
| * Test {@link TestDevice#getProductType()} when device is in fastboot and IDevice has not |
| * cached product type property |
| */ |
| public void testGetProductType_fastboot() throws DeviceNotAvailableException { |
| EasyMock.expect(mMockIDevice.arePropertiesSet()).andReturn(false); |
| CommandResult fastbootResult = new CommandResult(); |
| fastbootResult.setStatus(CommandStatus.SUCCESS); |
| // output of this cmd goes to stderr |
| fastbootResult.setStdout(""); |
| fastbootResult.setStderr("product: nexusone\n" + "finished. total time: 0.001s"); |
| EasyMock.expect( |
| mMockRunUtil.runTimedCmd(EasyMock.anyLong(), (String)EasyMock.anyObject(), |
| (String)EasyMock.anyObject(), (String)EasyMock.anyObject(), |
| (String)EasyMock.anyObject(), (String)EasyMock.anyObject())).andReturn( |
| fastbootResult); |
| EasyMock.replay(mMockIDevice, mMockRunUtil); |
| mRecoveryTestDevice.setDeviceState(TestDeviceState.FASTBOOT); |
| assertEquals("nexusone", mRecoveryTestDevice.getProductType()); |
| } |
| |
| /** |
| * Test {@link TestDevice#getProductType()} for a device with a non-alphanumeric fastboot |
| * product type |
| */ |
| public void testGetProductType_fastbootNonalpha() throws DeviceNotAvailableException { |
| EasyMock.expect(mMockIDevice.arePropertiesSet()).andReturn(false); |
| CommandResult fastbootResult = new CommandResult(); |
| fastbootResult.setStatus(CommandStatus.SUCCESS); |
| // output of this cmd goes to stderr |
| fastbootResult.setStdout(""); |
| fastbootResult.setStderr("product: foo-bar\n" + "finished. total time: 0.001s"); |
| EasyMock.expect( |
| mMockRunUtil.runTimedCmd(EasyMock.anyLong(), (String)EasyMock.anyObject(), |
| (String)EasyMock.anyObject(), (String)EasyMock.anyObject(), |
| (String)EasyMock.anyObject(), (String)EasyMock.anyObject())).andReturn( |
| fastbootResult); |
| EasyMock.replay(mMockIDevice, mMockRunUtil); |
| mRecoveryTestDevice.setDeviceState(TestDeviceState.FASTBOOT); |
| assertEquals("foo-bar", mRecoveryTestDevice.getProductType()); |
| } |
| |
| /** |
| * Verify that {@link TestDevice#getProductType()} throws an exception if requesting a product |
| * type directly fails while the device is in fastboot. |
| */ |
| public void testGetProductType_fastbootFail() throws DeviceNotAvailableException { |
| EasyMock.expect(mMockIDevice.arePropertiesSet()).andStubReturn(false); |
| CommandResult fastbootResult = new CommandResult(); |
| fastbootResult.setStatus(CommandStatus.SUCCESS); |
| // output of this cmd goes to stderr |
| fastbootResult.setStdout(""); |
| fastbootResult.setStderr("product: \n" + "finished. total time: 0.001s"); |
| EasyMock.expect( |
| mMockRunUtil.runTimedCmd(EasyMock.anyLong(), (String)EasyMock.anyObject(), |
| (String)EasyMock.anyObject(), (String)EasyMock.anyObject(), |
| (String)EasyMock.anyObject(), (String)EasyMock.anyObject())).andReturn( |
| fastbootResult).anyTimes(); |
| EasyMock.replay(mMockIDevice); |
| EasyMock.replay(mMockRunUtil); |
| mTestDevice.setDeviceState(TestDeviceState.FASTBOOT); |
| try { |
| String type = mTestDevice.getProductType(); |
| fail(String.format("DeviceNotAvailableException not thrown; productType was '%s'", |
| type)); |
| } catch (DeviceNotAvailableException e) { |
| // expected |
| } |
| } |
| |
| /** |
| * Test {@link TestDevice#getProductType()} when device is in adb and IDevice has not cached |
| * product type property |
| */ |
| public void testGetProductType_adb() throws Exception { |
| EasyMock.expect(mMockIDevice.arePropertiesSet()).andReturn(false); |
| final String expectedOutput = "nexusone"; |
| EasyMock.expect(mMockIDevice.getPropertyCacheOrSync("ro.hardware")).andReturn(expectedOutput); |
| EasyMock.replay(mMockIDevice); |
| assertEquals(expectedOutput, mTestDevice.getProductType()); |
| } |
| |
| /** |
| * Verify that {@link TestDevice#getProductType()} throws an exception if requesting a product |
| * type directly still fails. |
| */ |
| public void testGetProductType_adbFail() throws Exception { |
| EasyMock.expect(mMockIDevice.arePropertiesSet()).andStubReturn(false); |
| final String expectedOutput = ""; |
| EasyMock.expect(mMockIDevice.getPropertyCacheOrSync("ro.hardware")) |
| .andReturn(expectedOutput) |
| .times(3); |
| EasyMock.replay(mMockIDevice); |
| try { |
| mTestDevice.getProductType(); |
| fail("DeviceNotAvailableException not thrown"); |
| } catch (DeviceNotAvailableException e) { |
| // expected |
| } |
| } |
| |
| /** |
| * Test {@link TestDevice#clearErrorDialogs()} when both a error and anr dialog are present. |
| */ |
| public void testClearErrorDialogs() throws Exception { |
| final String anrOutput = "debugging=false crashing=false null notResponding=true " |
| + "com.android.server.am.AppNotRespondingDialog@4534aaa0 bad=false\n blah\n"; |
| final String crashOutput = "debugging=false crashing=true " |
| + "com.android.server.am.AppErrorDialog@45388a60 notResponding=false null bad=false" |
| + "blah \n"; |
| // construct a string with 2 error dialogs of each type to ensure proper detection |
| final String fourErrors = anrOutput + anrOutput + crashOutput + crashOutput; |
| injectShellResponse(null, fourErrors); |
| mMockIDevice.executeShellCommand((String)EasyMock.anyObject(), |
| (IShellOutputReceiver)EasyMock.anyObject(), EasyMock.anyInt()); |
| // expect 4 key events to be sent - one for each dialog |
| // and expect another dialog query - but return nothing |
| EasyMock.expectLastCall().times(5); |
| |
| EasyMock.replay(mMockIDevice); |
| mTestDevice.clearErrorDialogs(); |
| } |
| |
| /** |
| * Test the log file size limiting. |
| */ |
| public void testLogCatReceiver() throws IOException, InterruptedException, TimeoutException, |
| AdbCommandRejectedException, ShellCommandUnresponsiveException { |
| mTestDevice.setTmpLogcatSize(10); |
| final String input = "this is the output of greater than 10 bytes."; |
| final String input2 = "this is the second output of greater than 10 bytes."; |
| final String input3 = "<10bytes"; |
| final Object notifier = new Object(); |
| LogcatReceiver receiver = null; |
| |
| // mock the call to get system build id |
| EasyMock.expect(mMockIDevice.getProperty((String)EasyMock.anyObject())).andStubReturn("1"); |
| |
| try { |
| IAnswer<Object> shellAnswer = new IAnswer<Object>() { |
| @Override |
| public Object answer() throws Throwable { |
| IShellOutputReceiver receiver = |
| (IShellOutputReceiver)EasyMock.getCurrentArguments()[1]; |
| byte[] inputData = input.getBytes(); |
| // add log data > maximum. This will trigger a log swap, where inputData |
| // will be moved to the backup log file |
| receiver.addOutput(inputData, 0, inputData.length); |
| // inject the second input data > maximum. This will trigger another log |
| // swap, that will discard inputData. the backup log file will have |
| // inputData2, and the current log file will be empty |
| byte[] inputData2 = input2.getBytes(); |
| receiver.addOutput(inputData2, 0, inputData2.length); |
| // inject log data smaller than max log data - that will not trigger a |
| // log swap. The backup log file should contain inputData2, and the |
| // current should contain inputData3 |
| byte[] inputData3 = input3.getBytes(); |
| receiver.addOutput(inputData3, 0, inputData3.length); |
| synchronized (notifier) { |
| notifier.notify(); |
| try { |
| // block until interrupted |
| notifier.wait(); |
| } catch (InterruptedException e) { |
| } |
| } |
| return null; |
| } |
| }; |
| // expect shell command to be called, with any receiver |
| mMockIDevice.executeShellCommand((String)EasyMock.anyObject(), (IShellOutputReceiver) |
| EasyMock.anyObject(), EasyMock.eq(0)); |
| EasyMock.expectLastCall().andAnswer(shellAnswer); |
| EasyMock.replay(mMockIDevice); |
| receiver = mTestDevice.createLogcatReceiver(); |
| receiver.start(); |
| synchronized (notifier) { |
| notifier.wait(); |
| } |
| InputStreamSource iss = receiver.getLogcatData(); |
| String actualString = ""; |
| try { |
| actualString = StreamUtil.getStringFromStream(iss.createInputStream()); |
| } finally { |
| iss.cancel(); |
| } |
| // verify that data from both the backup log file (input2) and current log file |
| // (input3) is retrieved |
| assertFalse(actualString.contains(input)); |
| assertTrue(actualString.contains(input2)); |
| assertTrue(actualString.contains(input3)); |
| } finally { |
| if (receiver != null) { |
| receiver.stop(); |
| } |
| } |
| } |
| |
| public void testGetBugreport_deviceUnavail() throws Exception { |
| final String testCommand = "bugreport"; |
| final String expectedOutput = "this is the output\r\n in two lines\r\n"; |
| // FIXME: this isn't actually causing a DeviceNotAvailableException to be thrown |
| injectShellResponse(testCommand, expectedOutput); |
| mMockRecovery.recoverDevice(EasyMock.eq(mMockMonitor), EasyMock.eq(false)); |
| EasyMock.expectLastCall().andThrow(new DeviceNotAvailableException()); |
| |
| EasyMock.replay(mMockIDevice); |
| EasyMock.replay(mMockRecovery); |
| assertEquals(expectedOutput, StreamUtil.getStringFromStream( |
| mTestDevice.getBugreport().createInputStream())); |
| } |
| |
| /** |
| * Simple normal case test for |
| * {@link TestDevice#executeShellCommand(String, IShellOutputReceiver)}. |
| * <p/> |
| * Verify that the shell command is routed to the IDevice. |
| */ |
| public void testExecuteShellCommand_receiver() throws IOException, DeviceNotAvailableException, |
| TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException { |
| final String testCommand = "simple command"; |
| // expect shell command to be called |
| mMockIDevice.executeShellCommand(EasyMock.eq(testCommand), EasyMock.eq(mMockReceiver), |
| EasyMock.anyInt()); |
| EasyMock.replay(mMockIDevice); |
| mTestDevice.executeShellCommand(testCommand, mMockReceiver); |
| } |
| |
| /** |
| * Simple normal case test for |
| * {@link TestDevice#executeShellCommand(String)}. |
| * <p/> |
| * Verify that the shell command is routed to the IDevice, and shell output is collected. |
| */ |
| public void testExecuteShellCommand() throws Exception { |
| final String testCommand = "simple command"; |
| final String expectedOutput = "this is the output\r\n in two lines\r\n"; |
| injectShellResponse(testCommand, expectedOutput); |
| EasyMock.replay(mMockIDevice); |
| assertEquals(expectedOutput, mTestDevice.executeShellCommand(testCommand)); |
| } |
| |
| /** |
| * Test {@link TestDevice#executeShellCommand(String, IShellOutputReceiver)} behavior when |
| * {@link IDevice} throws IOException and recovery immediately fails. |
| * <p/> |
| * Verify that a DeviceNotAvailableException is thrown. |
| */ |
| public void testExecuteShellCommand_recoveryFail() throws Exception { |
| final String testCommand = "simple command"; |
| // expect shell command to be called |
| mMockIDevice.executeShellCommand(EasyMock.eq(testCommand), EasyMock.eq(mMockReceiver), |
| EasyMock.anyInt()); |
| EasyMock.expectLastCall().andThrow(new IOException()); |
| mMockRecovery.recoverDevice(EasyMock.eq(mMockMonitor), EasyMock.eq(false)); |
| EasyMock.expectLastCall().andThrow(new DeviceNotAvailableException()); |
| EasyMock.replay(mMockIDevice); |
| EasyMock.replay(mMockRecovery); |
| try { |
| mRecoveryTestDevice.executeShellCommand(testCommand, mMockReceiver); |
| fail("DeviceNotAvailableException not thrown"); |
| } catch (DeviceNotAvailableException e) { |
| // expected |
| } |
| } |
| |
| /** |
| * Test {@link TestDevice#executeShellCommand(String, IShellOutputReceiver)} behavior when |
| * {@link IDevice} throws IOException and device is in recovery until online mode. |
| * <p/> |
| * Verify that a DeviceNotAvailableException is thrown. |
| */ |
| public void testExecuteShellCommand_recoveryUntilOnline() throws Exception { |
| final String testCommand = "simple command"; |
| // expect shell command to be called |
| mRecoveryTestDevice.setRecoveryMode(RecoveryMode.ONLINE); |
| mMockIDevice.executeShellCommand(EasyMock.eq(testCommand), EasyMock.eq(mMockReceiver), |
| EasyMock.anyInt()); |
| EasyMock.expectLastCall().andThrow(new IOException()); |
| mMockRecovery.recoverDevice(EasyMock.eq(mMockMonitor), EasyMock.eq(true)); |
| setEnableAdbRootExpectations(); |
| mMockIDevice.executeShellCommand(EasyMock.eq(testCommand), EasyMock.eq(mMockReceiver), |
| EasyMock.anyInt()); |
| EasyMock.replay(mMockIDevice, mMockRecovery, mMockRunUtil, mMockMonitor); |
| mRecoveryTestDevice.executeShellCommand(testCommand, mMockReceiver); |
| } |
| |
| /** |
| * Test {@link TestDevice#executeShellCommand(String, IShellOutputReceiver)} behavior when |
| * {@link IDevice} throws IOException and recovery succeeds. |
| * <p/> |
| * Verify that command is re-tried. |
| */ |
| public void testExecuteShellCommand_recoveryRetry() throws Exception { |
| final String testCommand = "simple command"; |
| // expect shell command to be called |
| mMockIDevice.executeShellCommand(EasyMock.eq(testCommand), EasyMock.eq(mMockReceiver), |
| EasyMock.anyInt()); |
| EasyMock.expectLastCall().andThrow(new IOException()); |
| assertRecoverySuccess(); |
| mMockIDevice.executeShellCommand(EasyMock.eq(testCommand), EasyMock.eq(mMockReceiver), |
| EasyMock.anyInt()); |
| replayMocks(); |
| mTestDevice.executeShellCommand(testCommand, mMockReceiver); |
| } |
| |
| /** Set expectations for a successful recovery operation |
| */ |
| private void assertRecoverySuccess() throws DeviceNotAvailableException, IOException, |
| TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException { |
| mMockRecovery.recoverDevice(EasyMock.eq(mMockMonitor), EasyMock.eq(false)); |
| // expect post boot up steps |
| mMockIDevice.executeShellCommand(EasyMock.eq(mTestDevice.getDisableKeyguardCmd()), |
| (IShellOutputReceiver)EasyMock.anyObject(), EasyMock.anyInt()); |
| } |
| |
| /** |
| * Test {@link TestDevice#executeShellCommand(String, IShellOutputReceiver)} behavior when |
| * command times out and recovery succeeds. |
| * <p/> |
| * Verify that command is re-tried. |
| */ |
| public void testExecuteShellCommand_recoveryTimeoutRetry() throws Exception { |
| final String testCommand = "simple command"; |
| // expect shell command to be called - and never return from that call |
| mMockIDevice.executeShellCommand(EasyMock.eq(testCommand), EasyMock.eq(mMockReceiver), |
| EasyMock.anyInt()); |
| EasyMock.expectLastCall().andThrow(new TimeoutException()); |
| assertRecoverySuccess(); |
| // now expect shellCommand to be executed again, and succeed |
| mMockIDevice.executeShellCommand(EasyMock.eq(testCommand), EasyMock.eq(mMockReceiver), |
| EasyMock.anyInt()); |
| replayMocks(); |
| mTestDevice.executeShellCommand(testCommand, mMockReceiver); |
| } |
| |
| /** |
| * Test {@link TestDevice#executeShellCommand(String, IShellOutputReceiver)} behavior when |
| * {@link IDevice} repeatedly throws IOException and recovery succeeds. |
| * <p/> |
| * Verify that DeviceNotAvailableException is thrown. |
| */ |
| public void testExecuteShellCommand_recoveryAttempts() throws Exception { |
| final String testCommand = "simple command"; |
| // expect shell command to be called |
| mMockIDevice.executeShellCommand(EasyMock.eq(testCommand), EasyMock.eq(mMockReceiver), |
| EasyMock.anyInt()); |
| EasyMock.expectLastCall().andThrow(new IOException()).times( |
| TestDevice.MAX_RETRY_ATTEMPTS+1); |
| for (int i=0; i <= TestDevice.MAX_RETRY_ATTEMPTS; i++) { |
| assertRecoverySuccess(); |
| } |
| replayMocks(); |
| try { |
| mTestDevice.executeShellCommand(testCommand, mMockReceiver); |
| fail("DeviceUnresponsiveException not thrown"); |
| } catch (DeviceUnresponsiveException e) { |
| // expected |
| } |
| } |
| |
| /** |
| * Puts all the mock objects into replay mode |
| */ |
| private void replayMocks() { |
| EasyMock.replay(mMockIDevice, mMockRecovery, mMockMonitor, mMockRunUtil, mMockWifi); |
| } |
| |
| /** |
| * Verify all the mock objects |
| */ |
| private void verifyMocks() { |
| EasyMock.verify(mMockIDevice, mMockRecovery, mMockMonitor, mMockRunUtil, mMockWifi); |
| } |
| |
| |
| /** |
| * Unit test for {@link TestDevice#getExternalStoreFreeSpace()}. |
| * <p/> |
| * Verify that output of 'adb shell df' command is parsed correctly. |
| */ |
| public void testGetExternalStoreFreeSpace() throws Exception { |
| final String dfOutput = |
| "/mnt/sdcard: 3864064K total, 1282880K used, 2581184K available (block size 32768)"; |
| assertGetExternalStoreFreeSpace(dfOutput, 2581184); |
| } |
| |
| /** |
| * Unit test for {@link TestDevice#getExternalStoreFreeSpace()}. |
| * <p/> |
| * Verify that the table-based output of 'adb shell df' command is parsed correctly. |
| */ |
| public void testGetExternalStoreFreeSpace_table() throws Exception { |
| final String dfOutput = |
| "Filesystem Size Used Free Blksize\n" + |
| "/mnt/sdcard 3G 787M 2G 4096"; |
| assertGetExternalStoreFreeSpace(dfOutput, 2 * 1024 * 1024); |
| } |
| |
| /** |
| * Unit test for {@link TestDevice#getExternalStoreFreeSpace()}. |
| * <p/> |
| * Verify behavior when 'df' command returns unexpected content |
| */ |
| public void testGetExternalStoreFreeSpace_badOutput() throws Exception { |
| final String dfOutput = |
| "/mnt/sdcard: blaH"; |
| assertGetExternalStoreFreeSpace(dfOutput, 0); |
| } |
| |
| /** |
| * Helper method to verify the {@link TestDevice#getExternalStoreFreeSpace()} method under |
| * different conditions. |
| * |
| * @param dfOutput the test output to inject |
| * @param expectedFreeSpaceKB the expected free space |
| */ |
| private void assertGetExternalStoreFreeSpace(final String dfOutput, long expectedFreeSpaceKB) |
| throws Exception { |
| final String mntPoint = "/mnt/sdcard"; |
| final String expectedCmd = "df " + mntPoint; |
| EasyMock.expect(mMockMonitor.getMountPoint(IDevice.MNT_EXTERNAL_STORAGE)).andReturn( |
| mntPoint); |
| // expect shell command to be called, and return the test df output |
| injectShellResponse(expectedCmd, dfOutput); |
| EasyMock.replay(mMockIDevice, mMockMonitor); |
| assertEquals(expectedFreeSpaceKB, mTestDevice.getExternalStoreFreeSpace()); |
| } |
| |
| /** |
| * Unit test for {@link TestDevice#syncFiles)}. |
| * <p/> |
| * Verify behavior when given local file does not exist |
| */ |
| public void testSyncFiles_missingLocal() throws Exception { |
| EasyMock.replay(mMockIDevice); |
| assertFalse(mTestDevice.syncFiles(new File("idontexist"), "/sdcard")); |
| } |
| |
| /** |
| * Test {@link TestDevice#runInstrumentationTests(IRemoteAndroidTestRunner, Collection)} |
| * success case. |
| */ |
| public void testRunInstrumentationTests() throws Exception { |
| IRemoteAndroidTestRunner mockRunner = EasyMock.createMock(IRemoteAndroidTestRunner.class); |
| EasyMock.expect(mockRunner.getPackageName()).andStubReturn("com.example"); |
| Collection<ITestRunListener> listeners = new ArrayList<ITestRunListener>(0); |
| mockRunner.setMaxtimeToOutputResponse(EasyMock.anyInt()); |
| // expect runner.run command to be called |
| mockRunner.run(listeners); |
| EasyMock.replay(mockRunner); |
| mTestDevice.runInstrumentationTests(mockRunner, listeners); |
| } |
| |
| /** |
| * Test {@link TestDevice#runInstrumentationTests(IRemoteAndroidTestRunner, Collection)} |
| * when recovery fails. |
| */ |
| public void testRunInstrumentationTests_recoveryFails() throws Exception { |
| IRemoteAndroidTestRunner mockRunner = EasyMock.createMock(IRemoteAndroidTestRunner.class); |
| Collection<ITestRunListener> listeners = new ArrayList<ITestRunListener>(1); |
| ITestRunListener listener = EasyMock.createMock(ITestRunListener.class); |
| listeners.add(listener); |
| mockRunner.setMaxtimeToOutputResponse(EasyMock.anyInt()); |
| mockRunner.run(listeners); |
| EasyMock.expectLastCall().andThrow(new IOException()); |
| EasyMock.expect(mockRunner.getPackageName()).andReturn("foo"); |
| listener.testRunFailed((String)EasyMock.anyObject()); |
| mMockRecovery.recoverDevice(EasyMock.eq(mMockMonitor), EasyMock.eq(false)); |
| EasyMock.expectLastCall().andThrow(new DeviceNotAvailableException()); |
| EasyMock.replay(listener, mockRunner, mMockIDevice, mMockRecovery); |
| try { |
| mRecoveryTestDevice.runInstrumentationTests(mockRunner, listeners); |
| fail("DeviceNotAvailableException not thrown"); |
| } catch (DeviceNotAvailableException e) { |
| // expected |
| } |
| } |
| |
| /** |
| * Test {@link TestDevice#runInstrumentationTests(IRemoteAndroidTestRunner, Collection)} |
| * when recovery succeeds. |
| */ |
| public void testRunInstrumentationTests_recoverySucceeds() throws Exception { |
| IRemoteAndroidTestRunner mockRunner = EasyMock.createMock(IRemoteAndroidTestRunner.class); |
| Collection<ITestRunListener> listeners = new ArrayList<ITestRunListener>(1); |
| ITestRunListener listener = EasyMock.createMock(ITestRunListener.class); |
| listeners.add(listener); |
| mockRunner.setMaxtimeToOutputResponse(EasyMock.anyInt()); |
| mockRunner.run(listeners); |
| EasyMock.expectLastCall().andThrow(new IOException()); |
| EasyMock.expect(mockRunner.getPackageName()).andReturn("foo"); |
| listener.testRunFailed((String)EasyMock.anyObject()); |
| assertRecoverySuccess(); |
| EasyMock.replay(listener, mockRunner, mMockIDevice, mMockRecovery); |
| mTestDevice.runInstrumentationTests(mockRunner, listeners); |
| } |
| |
| /** |
| * Test {@link TestDevice#executeFastbootCommand(String...)} throws an exception when fastboot |
| * is not available. |
| */ |
| public void testExecuteFastbootCommand_nofastboot() throws Exception { |
| try { |
| mNoFastbootTestDevice.executeFastbootCommand(""); |
| fail("UnsupportedOperationException not thrown"); |
| } catch (UnsupportedOperationException e) { |
| // expected |
| } |
| } |
| |
| /** |
| * Test {@link TestDevice#executeLongFastbootCommand(String...)} throws an exception when |
| * fastboot is not available. |
| */ |
| public void testExecuteLongFastbootCommand_nofastboot() throws Exception { |
| try { |
| mNoFastbootTestDevice.executeFastbootCommand(""); |
| fail("UnsupportedOperationException not thrown"); |
| } catch (UnsupportedOperationException e) { |
| // expected |
| } |
| } |
| |
| /** |
| * Test that state changes are ignore while {@link TestDevice#executeFastbootCommand(String...)} |
| * is active. |
| * @throws InterruptedException |
| */ |
| public void testExecuteFastbootCommand_state() throws InterruptedException { |
| // build a fastboot response that will block |
| IAnswer<CommandResult> blockResult = new IAnswer<CommandResult>() { |
| @Override |
| public CommandResult answer() throws Throwable { |
| synchronized(this) { |
| // first inform this test that fastboot cmd is executing |
| notifyAll(); |
| // now wait for test to unblock us when its done testing logic |
| wait(1000); |
| } |
| return new CommandResult(CommandStatus.SUCCESS); |
| } |
| }; |
| EasyMock.expect(mMockRunUtil.runTimedCmd(EasyMock.anyLong(), EasyMock.eq("fastboot"), |
| EasyMock.eq("-s"),EasyMock.eq("serial"), EasyMock.eq("foo"))).andAnswer( |
| blockResult); |
| |
| // expect |
| mMockMonitor.setState(TestDeviceState.FASTBOOT); |
| mMockMonitor.setState(TestDeviceState.NOT_AVAILABLE); |
| replayMocks(); |
| |
| mTestDevice.setDeviceState(TestDeviceState.FASTBOOT); |
| assertEquals(TestDeviceState.FASTBOOT, mTestDevice.getDeviceState()); |
| |
| // start fastboot command in background thread |
| Thread fastbootThread = new Thread() { |
| @Override |
| public void run() { |
| try { |
| mTestDevice.executeFastbootCommand("foo"); |
| } catch (DeviceNotAvailableException e) { |
| CLog.e(e); |
| } |
| } |
| }; |
| fastbootThread.start(); |
| try { |
| synchronized (blockResult) { |
| blockResult.wait(1000); |
| } |
| // expect to ignore this |
| mTestDevice.setDeviceState(TestDeviceState.NOT_AVAILABLE); |
| assertEquals(TestDeviceState.FASTBOOT, mTestDevice.getDeviceState()); |
| } finally { |
| synchronized (blockResult) { |
| blockResult.notifyAll(); |
| } |
| } |
| fastbootThread.join(); |
| mTestDevice.setDeviceState(TestDeviceState.NOT_AVAILABLE); |
| assertEquals(TestDeviceState.NOT_AVAILABLE, mTestDevice.getDeviceState()); |
| } |
| |
| /** |
| * Test recovery mode is entered when fastboot command fails |
| */ |
| public void testExecuteFastbootCommand_recovery() throws UnsupportedOperationException, |
| DeviceNotAvailableException { |
| CommandResult result = new CommandResult(CommandStatus.EXCEPTION); |
| EasyMock.expect(mMockRunUtil.runTimedCmd(EasyMock.anyLong(), EasyMock.eq("fastboot"), |
| EasyMock.eq("-s"),EasyMock.eq("serial"), EasyMock.eq("foo"))).andReturn(result); |
| mMockRecovery.recoverDeviceBootloader((IDeviceStateMonitor)EasyMock.anyObject()); |
| CommandResult successResult = new CommandResult(CommandStatus.SUCCESS); |
| successResult.setStderr(""); |
| successResult.setStdout(""); |
| // now expect a successful retry |
| EasyMock.expect(mMockRunUtil.runTimedCmd(EasyMock.anyLong(), EasyMock.eq("fastboot"), |
| EasyMock.eq("-s"),EasyMock.eq("serial"), EasyMock.eq("foo"))).andReturn( |
| successResult); |
| replayMocks(); |
| mTestDevice.executeFastbootCommand("foo"); |
| verifyMocks(); |
| |
| } |
| |
| /** |
| * Basic test for encryption if encryption is not supported. |
| * <p> |
| * Calls {@link TestDevice#encryptDevice(boolean)}, {@link TestDevice#unlockDevice()}, and |
| * {@link TestDevice#unencryptDevice()} and makes sure that a |
| * {@link UnsupportedOperationException} is thrown for each method. |
| * </p> |
| */ |
| public void testEncryptionUnsupported() throws Exception { |
| setEncryptedUnsupportedExpectations(); |
| setEncryptedUnsupportedExpectations(); |
| setEncryptedUnsupportedExpectations(); |
| EasyMock.replay(mMockIDevice, mMockRunUtil, mMockMonitor); |
| |
| try { |
| mTestDevice.encryptDevice(false); |
| fail("encryptUserData() did not throw UnsupportedOperationException"); |
| } catch (UnsupportedOperationException e) { |
| // Expected |
| } |
| try { |
| mTestDevice.unlockDevice(); |
| fail("decryptUserData() did not throw UnsupportedOperationException"); |
| } catch (UnsupportedOperationException e) { |
| // Expected |
| } |
| try { |
| mTestDevice.unencryptDevice(); |
| fail("unencryptUserData() did not throw UnsupportedOperationException"); |
| } catch (UnsupportedOperationException e) { |
| // Expected |
| } |
| return; |
| } |
| |
| /** |
| * Configure EasyMock for a encryption check call, that returns that encryption is unsupported |
| */ |
| private void setEncryptedUnsupportedExpectations() throws Exception { |
| setEnableAdbRootExpectations(); |
| injectShellResponse("vdc cryptfs enablecrypto", "\r\n"); |
| } |
| |
| /** |
| * Simple test for {@link TestDevice#switchToAdbUsb()} |
| */ |
| public void testSwitchToAdbUsb() throws Exception { |
| EasyMock.expect(mMockRunUtil.runTimedCmd(EasyMock.anyLong(), EasyMock.eq("adb"), |
| EasyMock.eq("-s"), EasyMock.eq("serial"), EasyMock.eq("usb"))).andReturn( |
| new CommandResult(CommandStatus.SUCCESS)); |
| replayMocks(); |
| mTestDevice.switchToAdbUsb(); |
| verifyMocks(); |
| } |
| |
| /** |
| * Test for {@link TestDevice#switchToAdbTcp()} when device has no ip address |
| */ |
| public void testSwitchToAdbTcp_noIp() throws Exception { |
| EasyMock.expect(mMockWifi.getIpAddress()).andReturn(null); |
| replayMocks(); |
| assertNull(mTestDevice.switchToAdbTcp()); |
| verifyMocks(); |
| } |
| |
| /** |
| * Test normal success case for {@link TestDevice#switchToAdbTcp()}. |
| */ |
| public void testSwitchToAdbTcp() throws Exception { |
| EasyMock.expect(mMockWifi.getIpAddress()).andReturn("ip"); |
| EasyMock.expect(mMockRunUtil.runTimedCmd(EasyMock.anyLong(), EasyMock.eq("adb"), |
| EasyMock.eq("-s"), EasyMock.eq("serial"), EasyMock.eq("tcpip"), |
| EasyMock.eq("5555"))).andReturn( |
| new CommandResult(CommandStatus.SUCCESS)); |
| replayMocks(); |
| assertEquals("ip:5555", mTestDevice.switchToAdbTcp()); |
| verifyMocks(); |
| } |
| |
| /** |
| * Test simple success case for |
| * {@link TestDevice#installPackage(File, File, boolean, String...)}. |
| */ |
| public void testInstallPackages() throws Exception { |
| final String certFile = "foo.dc"; |
| final String apkFile = "foo.apk"; |
| EasyMock.expect(mMockIDevice.syncPackageToDevice(EasyMock.contains(certFile))).andReturn( |
| certFile); |
| EasyMock.expect(mMockIDevice.syncPackageToDevice(EasyMock.contains(apkFile))).andReturn( |
| apkFile); |
| // expect apk path to be passed as extra arg |
| EasyMock.expect( |
| mMockIDevice.installRemotePackage(EasyMock.eq(certFile), EasyMock.eq(true), |
| EasyMock.eq("-l"), EasyMock.contains(apkFile))).andReturn(null); |
| mMockIDevice.removeRemotePackage(certFile); |
| mMockIDevice.removeRemotePackage(apkFile); |
| |
| replayMocks(); |
| |
| assertNull(mTestDevice.installPackage(new File(apkFile), new File(certFile), true, "-l")); |
| } |
| |
| /** |
| * Helper method to build a response to a executeShellCommand call |
| * |
| * @param expectedCommand the shell command to expect or null to skip verification of command |
| * @param response the response to simulate |
| */ |
| private void injectShellResponse(final String expectedCommand, final String response) |
| throws Exception { |
| injectShellResponse(expectedCommand, response, false); |
| } |
| |
| /** |
| * Helper method to build a response to a executeShellCommand call |
| * |
| * @param expectedCommand the shell command to expect or null to skip verification of command |
| * @param response the response to simulate |
| * @param asStub whether to set a single expectation or a stub expectation |
| */ |
| @SuppressWarnings("unchecked") |
| private void injectShellResponse(final String expectedCommand, final String response, |
| boolean asStub) throws Exception { |
| IAnswer shellAnswer = new IAnswer() { |
| @Override |
| public Object answer() throws Throwable { |
| IShellOutputReceiver receiver = |
| (IShellOutputReceiver)EasyMock.getCurrentArguments()[1]; |
| byte[] inputData = response.getBytes(); |
| receiver.addOutput(inputData, 0, inputData.length); |
| return null; |
| } |
| }; |
| if (expectedCommand != null) { |
| mMockIDevice.executeShellCommand(EasyMock.eq(expectedCommand), |
| (IShellOutputReceiver)EasyMock.anyObject(), |
| EasyMock.anyInt()); |
| } else { |
| mMockIDevice.executeShellCommand((String)EasyMock.anyObject(), |
| (IShellOutputReceiver)EasyMock.anyObject(), |
| EasyMock.anyInt()); |
| |
| } |
| if (asStub) { |
| EasyMock.expectLastCall().andStubAnswer(shellAnswer); |
| } else { |
| EasyMock.expectLastCall().andAnswer(shellAnswer); |
| } |
| } |
| |
| /** |
| * Test normal success case for {@link TestDevice#reboot()} |
| */ |
| public void testReboot() throws Exception { |
| EasyMock.expect(mMockMonitor.waitForDeviceOnline()).andReturn( |
| mMockIDevice); |
| setEnableAdbRootExpectations(); |
| setEncryptedUnsupportedExpectations(); |
| EasyMock.expect(mMockMonitor.waitForDeviceAvailable(EasyMock.anyLong())).andReturn( |
| mMockIDevice); |
| replayMocks(); |
| mTestDevice.reboot(); |
| verifyMocks(); |
| } |
| |
| /** |
| * Test {@link TestDevice#reboot()} attempts a recovery upon failure |
| */ |
| public void testRebootRecovers() throws Exception { |
| EasyMock.expect(mMockMonitor.waitForDeviceOnline()).andReturn( |
| mMockIDevice); |
| setEnableAdbRootExpectations(); |
| setEncryptedUnsupportedExpectations(); |
| EasyMock.expect(mMockMonitor.waitForDeviceAvailable(EasyMock.anyLong())).andReturn(null); |
| mMockRecovery.recoverDevice(mMockMonitor, false); |
| replayMocks(); |
| mRecoveryTestDevice.reboot(); |
| verifyMocks(); |
| } |
| |
| /** |
| * Unit test for {@link TestDevice#getInstalledPackageNames()}. |
| */ |
| public void testGetInstalledPackageNames() throws Exception { |
| final String output = "package:/system/app/LiveWallpapers.apk=com.android.wallpaper\n" + |
| "package:/system/app/LiveWallpapersPicker.apk=com.android.wallpaper.livepicker"; |
| injectShellResponse(TestDevice.LIST_PACKAGES_CMD, output); |
| EasyMock.replay(mMockIDevice, mMockMonitor); |
| Set<String> actualPkgs = mTestDevice.getInstalledPackageNames(); |
| assertEquals(2, actualPkgs.size()); |
| assertTrue(actualPkgs.contains("com.android.wallpaper")); |
| assertTrue(actualPkgs.contains("com.android.wallpaper.livepicker")); |
| } |
| |
| /** |
| * Unit test for {@link TestDevice#getInstalledNonSystemPackageNames()}. |
| */ |
| public void testGetInstalledNonSystemPackageNames() throws Exception { |
| final String output = "package:/data/app/LiveWallpapers.apk=com.android.wallpaper\n" + |
| "package:/system/app/LiveWallpapersPicker.apk=com.android.wallpaper.livepicker"; |
| injectShellResponse(TestDevice.LIST_PACKAGES_CMD, output); |
| EasyMock.replay(mMockIDevice, mMockMonitor); |
| Set<String> actualPkgs = mTestDevice.getInstalledNonSystemPackageNames(); |
| assertEquals(1, actualPkgs.size()); |
| assertTrue(actualPkgs.contains("com.android.wallpaper")); |
| } |
| |
| /** |
| * Unit test for {@link TestDevice#getInstalledPackageNames()}. |
| * <p/> |
| * Test bad output. |
| */ |
| public void testGetInstalledPackageNamesForBadOutput() throws Exception { |
| final String output = "junk output"; |
| injectShellResponse(TestDevice.LIST_PACKAGES_CMD, output); |
| EasyMock.replay(mMockIDevice, mMockMonitor); |
| Set<String> actualPkgs = mTestDevice.getInstalledPackageNames(); |
| assertEquals(0, actualPkgs.size()); |
| } |
| |
| /** |
| * Unit test to make sure that the simple convenience constructor for |
| * {@link ITestDevice#MountPointInfo} works as expected. |
| */ |
| public void testMountInfo_simple() throws Exception { |
| List<String> empty = Collections.emptyList(); |
| MountPointInfo info = new MountPointInfo("filesystem", "mountpoint", "type", empty); |
| assertEquals("filesystem", info.filesystem); |
| assertEquals("mountpoint", info.mountpoint); |
| assertEquals("type", info.type); |
| assertEquals(empty, info.options); |
| } |
| |
| /** |
| * Unit test to make sure that the mount-option-parsing convenience constructor for |
| * {@link ITestDevice#MountPointInfo} works as expected. |
| */ |
| public void testMountInfo_parseOptions() throws Exception { |
| MountPointInfo info = new MountPointInfo("filesystem", "mountpoint", "type", "rw,relatime"); |
| assertEquals("filesystem", info.filesystem); |
| assertEquals("mountpoint", info.mountpoint); |
| assertEquals("type", info.type); |
| |
| // options should be parsed |
| assertNotNull(info.options); |
| assertEquals(2, info.options.size()); |
| assertEquals("rw", info.options.get(0)); |
| assertEquals("relatime", info.options.get(1)); |
| } |
| |
| /** |
| * A unit test to ensure {@link TestDevice#getMountPointInfo()} works as expected. |
| */ |
| public void testGetMountPointInfo() throws Exception { |
| injectShellResponse("cat /proc/mounts", ArrayUtil.join("\r\n", |
| "rootfs / rootfs ro,relatime 0 0", |
| "tmpfs /dev tmpfs rw,nosuid,relatime,mode=755 0 0", |
| "devpts /dev/pts devpts rw,relatime,mode=600 0 0", |
| "proc /proc proc rw,relatime 0 0", |
| "sysfs /sys sysfs rw,relatime 0 0", |
| "none /acct cgroup rw,relatime,cpuacct 0 0", |
| "tmpfs /mnt/asec tmpfs rw,relatime,mode=755,gid=1000 0 0", |
| "tmpfs /mnt/obb tmpfs rw,relatime,mode=755,gid=1000 0 0", |
| "none /dev/cpuctl cgroup rw,relatime,cpu 0 0", |
| "/dev/block/vold/179:3 /mnt/secure/asec vfat rw,dirsync,nosuid,nodev," + |
| "noexec,relatime,uid=1000,gid=1015,fmask=0702,dmask=0702," + |
| "allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed," + |
| "utf8,errors=remount-ro 0 0", |
| "tmpfs /storage/sdcard0/.android_secure tmpfs " + |
| "ro,relatime,size=0k,mode=000 0 0")); |
| replayMocks(); |
| List<MountPointInfo> info = mTestDevice.getMountPointInfo(); |
| verifyMocks(); |
| assertEquals(11, info.size()); |
| |
| // spot-check |
| MountPointInfo mpi = info.get(0); |
| assertEquals("rootfs", mpi.filesystem); |
| assertEquals("/", mpi.mountpoint); |
| assertEquals("rootfs", mpi.type); |
| assertEquals(2, mpi.options.size()); |
| assertEquals("ro", mpi.options.get(0)); |
| assertEquals("relatime", mpi.options.get(1)); |
| |
| mpi = info.get(9); |
| assertEquals("/dev/block/vold/179:3", mpi.filesystem); |
| assertEquals("/mnt/secure/asec", mpi.mountpoint); |
| assertEquals("vfat", mpi.type); |
| assertEquals(16, mpi.options.size()); |
| assertEquals("dirsync", mpi.options.get(1)); |
| assertEquals("errors=remount-ro", mpi.options.get(15)); |
| } |
| |
| /** |
| * A unit test to ensure {@link TestDevice#getMountPointInfo(String)} works as expected. |
| */ |
| public void testGetMountPointInfo_filter() throws Exception { |
| injectShellResponse("cat /proc/mounts", ArrayUtil.join("\r\n", |
| "rootfs / rootfs ro,relatime 0 0", |
| "tmpfs /dev tmpfs rw,nosuid,relatime,mode=755 0 0", |
| "devpts /dev/pts devpts rw,relatime,mode=600 0 0", |
| "proc /proc proc rw,relatime 0 0", |
| "sysfs /sys sysfs rw,relatime 0 0", |
| "none /acct cgroup rw,relatime,cpuacct 0 0", |
| "tmpfs /mnt/asec tmpfs rw,relatime,mode=755,gid=1000 0 0", |
| "tmpfs /mnt/obb tmpfs rw,relatime,mode=755,gid=1000 0 0", |
| "none /dev/cpuctl cgroup rw,relatime,cpu 0 0", |
| "/dev/block/vold/179:3 /mnt/secure/asec vfat rw,dirsync,nosuid,nodev," + |
| "noexec,relatime,uid=1000,gid=1015,fmask=0702,dmask=0702," + |
| "allow_utime=0020,codepage=cp437,iocharset=iso8859-1,shortname=mixed," + |
| "utf8,errors=remount-ro 0 0", |
| "tmpfs /storage/sdcard0/.android_secure tmpfs " + |
| "ro,relatime,size=0k,mode=000 0 0"), |
| true /* asStub */); |
| replayMocks(); |
| MountPointInfo mpi = mTestDevice.getMountPointInfo("/mnt/secure/asec"); |
| assertEquals("/dev/block/vold/179:3", mpi.filesystem); |
| assertEquals("/mnt/secure/asec", mpi.mountpoint); |
| assertEquals("vfat", mpi.type); |
| assertEquals(16, mpi.options.size()); |
| assertEquals("dirsync", mpi.options.get(1)); |
| assertEquals("errors=remount-ro", mpi.options.get(15)); |
| |
| assertNull(mTestDevice.getMountPointInfo("/a/mountpoint/too/far")); |
| } |
| |
| public void testParseFreeSpaceFromFree() throws Exception { |
| assertNotNull("Failed to parse free space size with decimal point", |
| mTestDevice.parseFreeSpaceFromFree("/storage/emulated/legacy", |
| "/storage/emulated/legacy 13.2G 296.4M 12.9G 4096")); |
| assertNotNull("Failed to parse integer free space size", |
| mTestDevice.parseFreeSpaceFromFree("/storage/emulated/legacy", |
| "/storage/emulated/legacy 13G 395M 12G 4096")); |
| } |
| } |
| |