/** 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);
    }
  }
  /** 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);
    }
  }
  /** {@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();
    mMockBuildInfo = new DeviceBuildInfo("0", "", "");
    mMockBuildInfo.setBuildFlavor("flavor");
    mDeviceFlashPreparer =
        new DeviceFlashPreparer() {
          @Override
          protected IDeviceFlasher createFlasher(ITestDevice device) {
            return mMockFlasher;
          }

          @Override
          int getDeviceBootPollTimeMs() {
            return 100;
          }
        };
    mDeviceFlashPreparer.setDeviceBootTime(100);
    // expect this call
    mMockFlasher.setUserDataFlashOption(UserDataFlashOption.FLASH);
    mTmpDir = FileUtil.createTempDir("tmp");
  }
 /** 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);
   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"));
   mMockDevice.setRecoveryMode(RecoveryMode.AVAILABLE);
   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);
 }
 /**
  * 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
   }
 }
 /** 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);
 }