/** Multi threaded {@link ConcurrentIdBasedLockManager} test. */
  @Test
  public void multithreadedConcurrentLockManagerTest() {
    final IdBasedLockManager<String> lockManager = new ConcurrentIdBasedLockManager<>();
    lockManagerTestExecutor(lockManager, LOCKS_IDS);

    // checking results
    Assert.assertEquals(0, lockManager.getLocksCount());
    Assert.assertNotNull(lockManager.getLocksIds());
    Assert.assertEquals(0, lockManager.getLocksIds().size());

    int processedTotal = 0;
    int unsafeTotal = 0;
    for (final String id : LOCKS_IDS) {
      final int processed = PROCESSED_PER_ID_CALLS.get(id).get();
      processedTotal += processed;
      final int unsafe = UNSAFE_PER_ID_CALLS.get(id).get();
      unsafeTotal += unsafe;

      Assert.assertEquals(1, ACTIVE_MAX_PER_ID_CALLS.get(id).get()); // should be not more then 1
    }

    Assert.assertEquals(THREADS * CALLS_PER_THREAD, processedTotal);
    Assert.assertTrue(THREADS >= ACTIVE_MAX_CALLS.get()); // should be not more then threads amount
    Assert.assertEquals(0, unsafeTotal);
  }
  /** Basic {@link ConcurrentIdBasedLockManager} test. */
  @Test
  public void basicConcurrentLockManagerTest() {
    IdBasedLockManager<String> lockManager = new ConcurrentIdBasedLockManager<>();
    Assert.assertNotNull(lockManager.getLocksIds());
    Assert.assertEquals(0, lockManager.getLocksIds().size());

    IdBasedLock<String> lock = lockManager.obtainLock(LOCK_ID);
    Assert.assertNotNull(lock);
    Assert.assertNotNull(lockManager.getLocksIds());
    Assert.assertEquals(1, lockManager.getLocksIds().size());
    Assert.assertNotNull(lockManager.getLocksIds().get(0));
    Assert.assertEquals(LOCK_ID, lockManager.getLocksIds().get(0));

    lock.lock();
    try {
      Assert.assertEquals(LOCK_ID, lock.getId());
      Assert.assertEquals(1, lock.getReferencesCount());
      Assert.assertNotNull(lock.toString());
    } finally {
      lock.unlock();
    }

    Assert.assertNotNull(lockManager.getLocksIds());
    Assert.assertEquals(0, lockManager.getLocksIds().size());
  }
    @Override
    public void run() {
      try {
        starter.await();
      } catch (final InterruptedException e) {
        Assert.fail();
      }

      for (int i = 0; i < CALLS_PER_THREAD; i++) {
        final String id = getRandom(ids);
        final IdBasedLock<String> lock = lockManager.obtainLock(id);
        lock.lock();

        int activeCount = ACTIVE_CALLS.incrementAndGet();
        if (activeCount > ACTIVE_MAX_CALLS.get()) ACTIVE_MAX_CALLS.set(activeCount);

        int activePerIdCount = ACTIVE_PER_ID_CALLS.get(id).incrementAndGet();
        if (activePerIdCount > ACTIVE_MAX_PER_ID_CALLS.get(id).get())
          ACTIVE_MAX_PER_ID_CALLS.get(id).set(activePerIdCount);

        if (activePerIdCount > 1) UNSAFE_PER_ID_CALLS.get(id).incrementAndGet();

        ACTIVE_PER_ID_CALLS.get(id).decrementAndGet();

        ACTIVE_CALLS.decrementAndGet();

        lock.unlock();

        PROCESSED_PER_ID_CALLS.get(id).incrementAndGet();
      }

      finisher.countDown();
    }
 /** Error cases test. */
 @Test
 public void errorCasesTest() {
   // safe lock manager testing
   IdBasedLockManager<String> lockManager = new SafeIdBasedLockManager<>();
   try {
     lockManager.obtainLock(null);
     Assert.fail();
   } catch (final IllegalArgumentException e) {
     Assert.assertTrue(e.getMessage().startsWith("id"));
   }
   try {
     lockManager.releaseLock(null);
     Assert.fail();
   } catch (final IllegalArgumentException e) {
     Assert.assertTrue(e.getMessage().startsWith("lock"));
   }
 }