blob: 232035a2a4b200df874f228d6a1b951c952f0b3f [file] [log] [blame]
/*
* 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.targetprep;
import com.android.tradefed.build.DeviceBuildInfo;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.build.IDeviceBuildInfo;
import com.android.tradefed.command.remote.DeviceDescriptor;
import com.android.tradefed.device.DeviceAllocationState;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.DeviceUnresponsiveException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.device.ITestDevice.RecoveryMode;
import com.android.tradefed.device.TestDeviceOptions;
import com.android.tradefed.host.IHostOptions;
import com.android.tradefed.targetprep.IDeviceFlasher.UserDataFlashOption;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.RunUtil;
import junit.framework.TestCase;
import org.easymock.EasyMock;
import java.io.File;
import java.util.Arrays;
import java.util.concurrent.Semaphore;
/**
* Unit tests for {@link DeviceFlashPreparer}.
*/
public class DeviceFlashPreparerTest extends TestCase {
private IDeviceFlasher mMockFlasher;
private DeviceFlashPreparer mDeviceFlashPreparer;
private ITestDevice mMockDevice;
private IDeviceBuildInfo mMockBuildInfo;
private IHostOptions mMockHostOptions;
private File mTmpDir;
/**
* {@inheritDoc}
*/
@Override
protected void setUp() throws Exception {
super.setUp();
mMockFlasher = EasyMock.createMock(IDeviceFlasher.class);
mMockDevice = EasyMock.createMock(ITestDevice.class);
EasyMock.expect(mMockDevice.getSerialNumber()).andReturn("foo").anyTimes();
EasyMock.expect(mMockDevice.getOptions()).andReturn(new TestDeviceOptions()).anyTimes();
mMockBuildInfo = new DeviceBuildInfo("0", "");
mMockBuildInfo.setDeviceImageFile(new File("foo"), "0");
mMockBuildInfo.setBuildFlavor("flavor");
mMockHostOptions = EasyMock.createMock(IHostOptions.class);
mDeviceFlashPreparer = new DeviceFlashPreparer() {
@Override
protected IDeviceFlasher createFlasher(ITestDevice device) {
return mMockFlasher;
}
@Override
int getDeviceBootPollTimeMs() {
return 100;
}
@Override
IHostOptions getHostOptions() {
return mMockHostOptions;
}
};
// Reset default settings
mDeviceFlashPreparer.setConcurrentFlashSettings(null, null, true);
mDeviceFlashPreparer.setDeviceBootTime(100);
// expect this call
mMockFlasher.setUserDataFlashOption(UserDataFlashOption.FLASH);
mTmpDir = FileUtil.createTempDir("tmp");
}
/**
* {@inheritDoc}
*/
@Override
protected void tearDown() throws Exception {
FileUtil.recursiveDelete(mTmpDir);
super.tearDown();
}
/**
* Simple normal case test for {@link DeviceSetup#setUp(ITestDevice, IBuildInfo)}.
*/
public void testSetup() throws Exception {
doSetupExpectations();
EasyMock.replay(mMockFlasher, mMockDevice);
mDeviceFlashPreparer.setUp(mMockDevice, mMockBuildInfo);
EasyMock.verify(mMockFlasher, mMockDevice);
}
/**
* Set EasyMock expectations for a normal setup call
*/
private void doSetupExpectations() throws TargetSetupError, DeviceNotAvailableException {
mMockDevice.setRecoveryMode(RecoveryMode.ONLINE);
mMockFlasher.overrideDeviceOptions(mMockDevice);
mMockFlasher.setForceSystemFlash(false);
mMockFlasher.setDataWipeSkipList(Arrays.asList(new String[]{}));
mMockFlasher.flash(mMockDevice, mMockBuildInfo);
mMockFlasher.setWipeTimeout(EasyMock.anyLong());
mMockDevice.waitForDeviceOnline();
EasyMock.expect(mMockDevice.enableAdbRoot()).andStubReturn(Boolean.TRUE);
mMockDevice.setDate(null);
EasyMock.expect(mMockDevice.getBuildId()).andReturn(mMockBuildInfo.getBuildId());
EasyMock.expect(mMockDevice.getBuildFlavor()).andReturn(mMockBuildInfo.getBuildFlavor());
EasyMock.expect(mMockDevice.isEncryptionSupported()).andStubReturn(Boolean.TRUE);
EasyMock.expect(mMockDevice.isDeviceEncrypted()).andStubReturn(Boolean.FALSE);
mMockDevice.clearLogcat();
mMockDevice.waitForDeviceAvailable(EasyMock.anyLong());
mMockDevice.setRecoveryMode(RecoveryMode.AVAILABLE);
mMockDevice.postBootSetup();
}
/**
* Test {@link DeviceSetup#setUp(ITestDevice, IBuildInfo)} when a non IDeviceBuildInfo type
* is provided
*/
public void testSetUp_nonDevice() throws Exception {
try {
mDeviceFlashPreparer.setUp(mMockDevice, EasyMock.createMock(IBuildInfo.class));
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
// expected
}
}
/**
* Test {@link DeviceSetup#setUp(ITestDevice, IBuildInfo)} when build does not boot
*/
public void testSetup_buildError() throws Exception {
mMockDevice.setRecoveryMode(RecoveryMode.ONLINE);
mMockFlasher.overrideDeviceOptions(mMockDevice);
mMockFlasher.setForceSystemFlash(false);
mMockFlasher.setDataWipeSkipList(Arrays.asList(new String[]{}));
mMockFlasher.flash(mMockDevice, mMockBuildInfo);
mMockFlasher.setWipeTimeout(EasyMock.anyLong());
mMockDevice.waitForDeviceOnline();
EasyMock.expect(mMockDevice.enableAdbRoot()).andStubReturn(Boolean.TRUE);
mMockDevice.setDate(null);
EasyMock.expect(mMockDevice.getBuildId()).andReturn(mMockBuildInfo.getBuildId());
EasyMock.expect(mMockDevice.getBuildFlavor()).andReturn(mMockBuildInfo.getBuildFlavor());
EasyMock.expect(mMockDevice.isEncryptionSupported()).andStubReturn(Boolean.TRUE);
EasyMock.expect(mMockDevice.isDeviceEncrypted()).andStubReturn(Boolean.FALSE);
mMockDevice.clearLogcat();
mMockDevice.waitForDeviceAvailable(EasyMock.anyLong());
EasyMock.expectLastCall().andThrow(new DeviceUnresponsiveException("foo", "fakeserial"));
mMockDevice.setRecoveryMode(RecoveryMode.AVAILABLE);
EasyMock.expect(mMockDevice.getDeviceDescriptor()).andReturn(
new DeviceDescriptor("SERIAL", false, DeviceAllocationState.Available, "unknown",
"unknown", "unknown", "unknown", "unknown"));
EasyMock.replay(mMockFlasher, mMockDevice);
try {
mDeviceFlashPreparer.setUp(mMockDevice, mMockBuildInfo);
fail("DeviceFlashPreparerTest not thrown");
} catch (BuildError e) {
// expected; use the general version to make absolutely sure that
// DeviceFailedToBootError properly masquerades as a BuildError.
assertTrue(e instanceof DeviceFailedToBootError);
}
EasyMock.verify(mMockFlasher, mMockDevice);
}
/**
* Ensure that the flasher instance limiting machinery is working as expected.
*/
public void testFlashLimit() throws Exception {
final DeviceFlashPreparer dfp = mDeviceFlashPreparer;
try {
Thread waiter = new Thread() {
@Override
public void run() {
dfp.takeFlashingPermit();
dfp.returnFlashingPermit();
}
};
dfp.setConcurrentFlashSettings(1, new Semaphore(1), true);
// take the permit; the next attempt to take the permit should block
dfp.takeFlashingPermit();
assertFalse(dfp.getConcurrentFlashLock().hasQueuedThreads());
waiter.start();
RunUtil.getDefault().sleep(100); // Thread start should take <100ms
assertTrue("Invalid state: waiter thread is not alive", waiter.isAlive());
assertTrue("No queued threads", dfp.getConcurrentFlashLock().hasQueuedThreads());
dfp.returnFlashingPermit();
RunUtil.getDefault().sleep(100); // Thread start should take <100ms
assertFalse("Unexpected queued threads",
dfp.getConcurrentFlashLock().hasQueuedThreads());
waiter.join(1000);
assertFalse("waiter thread has not returned", waiter.isAlive());
} finally {
// Attempt to reset concurrent flash settings to defaults
dfp.setConcurrentFlashSettings(null, null, true);
}
}
/**
* Ensure that the flasher limiting respects {@link IHostOptions}.
*/
public void testFlashLimit_withHostOptions() throws Exception {
final DeviceFlashPreparer dfp = mDeviceFlashPreparer;
try {
Thread waiter = new Thread() {
@Override
public void run() {
dfp.takeFlashingPermit();
dfp.returnFlashingPermit();
}
};
EasyMock.expect(mMockHostOptions.getConcurrentFlasherLimit()).andReturn(1).anyTimes();
EasyMock.replay(mMockHostOptions);
// take the permit; the next attempt to take the permit should block
dfp.takeFlashingPermit();
assertFalse(dfp.getConcurrentFlashLock().hasQueuedThreads());
waiter.start();
RunUtil.getDefault().sleep(100); // Thread start should take <100ms
assertTrue("Invalid state: waiter thread is not alive", waiter.isAlive());
assertTrue("No queued threads", dfp.getConcurrentFlashLock().hasQueuedThreads());
dfp.returnFlashingPermit();
RunUtil.getDefault().sleep(100); // Thread start should take <100ms
assertFalse("Unexpected queued threads",
dfp.getConcurrentFlashLock().hasQueuedThreads());
waiter.join(1000);
assertFalse("waiter thread has not returned", waiter.isAlive());
EasyMock.verify(mMockHostOptions);
} finally {
// Attempt to reset concurrent flash settings to defaults
dfp.setConcurrentFlashSettings(null, null, true);
}
}
/**
* Ensure that the flasher instance limiting machinery is working as expected.
*/
public void testUnlimitedFlashLimit() throws Exception {
final DeviceFlashPreparer dfp = mDeviceFlashPreparer;
try {
Thread waiter = new Thread() {
@Override
public void run() {
dfp.takeFlashingPermit();
dfp.returnFlashingPermit();
}
};
dfp.setConcurrentFlashSettings(null, null, true);
// take a permit; the next attempt to take the permit should proceed without blocking
dfp.takeFlashingPermit();
assertNull("Flash lock is non-null", dfp.getConcurrentFlashLock());
waiter.start();
RunUtil.getDefault().sleep(100); // Thread start should take <100ms
Thread.State waiterState = waiter.getState();
assertTrue("Invalid state: waiter thread hasn't started",
waiter.isAlive() || Thread.State.TERMINATED.equals(waiterState));
assertNull("Flash lock is non-null", dfp.getConcurrentFlashLock());
dfp.returnFlashingPermit();
RunUtil.getDefault().sleep(100); // Thread start should take <100ms
assertNull("Flash lock is non-null", dfp.getConcurrentFlashLock());
waiter.join(1000);
assertFalse("waiter thread has not returned", waiter.isAlive());
} finally {
// Attempt to reset concurrent flash settings to defaults
dfp.setConcurrentFlashSettings(null, null, true);
}
}
}