private void testLockMigration(int nodeThatPuts, boolean commit) throws Exception {
    Map<Object, Transaction> key2Tx = new HashMap<Object, Transaction>();
    for (int i = 0; i < NUM_KEYS; i++) {
      Object key = getKeyForCache(0);
      if (key2Tx.containsKey(key)) continue;

      // put a key to have some data in cache
      cache(nodeThatPuts).put(key, key);

      // start a TX that locks the key and then we suspend it
      tm(nodeThatPuts).begin();
      Transaction tx = tm(nodeThatPuts).getTransaction();
      advancedCache(nodeThatPuts).lock(key);
      tm(nodeThatPuts).suspend();
      key2Tx.put(key, tx);

      assertLocked(0, key);
    }

    log.trace("Lock transfer happens here");

    // add a third node hoping that some of the previously created keys will be migrated to it
    addClusterEnabledCacheManager(dccc);
    waitForClusterToForm();

    // search for a key that was migrated to third node and the suspended TX that locked it
    Object migratedKey = null;
    Transaction migratedTransaction = null;
    ConsistentHash consistentHash = advancedCache(2).getDistributionManager().getConsistentHash();
    for (Object key : key2Tx.keySet()) {
      if (consistentHash.locatePrimaryOwner(key).equals(address(2))) {
        migratedKey = key;
        migratedTransaction = key2Tx.get(key);
        log.trace("Migrated key = " + migratedKey);
        log.trace(
            "Migrated transaction = "
                + ((DummyTransaction) migratedTransaction).getEnlistedResources());
        break;
      }
    }

    // we do not focus on the other transactions so we commit them now
    log.trace("Committing all transactions except the migrated one.");
    for (Object key : key2Tx.keySet()) {
      if (!key.equals(migratedKey)) {
        Transaction tx = key2Tx.get(key);
        tm(nodeThatPuts).resume(tx);
        tm(nodeThatPuts).commit();
      }
    }

    if (migratedKey == null) {
      // this could happen in extreme cases
      log.trace("No key migrated to new owner - test cannot be performed!");
    } else {
      // the migrated TX is resumed and committed or rolled back. we expect the migrated key to be
      // unlocked now
      tm(nodeThatPuts).resume(migratedTransaction);
      if (commit) {
        tm(nodeThatPuts).commit();
      } else {
        tm(nodeThatPuts).rollback();
      }

      // there should not be any locks
      assertNotLocked(cache(0), migratedKey);
      assertNotLocked(cache(1), migratedKey);
      assertNotLocked(cache(2), migratedKey);

      // if a new TX tries to write to the migrated key this should not fail, the key should not be
      // locked
      tm(nodeThatPuts).begin();
      cache(nodeThatPuts)
          .put(
              migratedKey,
              "someValue"); // this should not result in TimeoutException due to key still locked
      tm(nodeThatPuts).commit();
    }

    log.trace("Checking the values from caches...");
    for (Object key : key2Tx.keySet()) {
      log.tracef("Checking key: %s", key);
      Object expectedValue = key;
      if (key.equals(migratedKey)) {
        expectedValue = "someValue";
      }
      // check them directly in data container
      InternalCacheEntry d0 = advancedCache(0).getDataContainer().get(key);
      InternalCacheEntry d1 = advancedCache(1).getDataContainer().get(key);
      InternalCacheEntry d2 = advancedCache(2).getDataContainer().get(key);
      int c = 0;
      if (d0 != null && !d0.isExpired(TIME_SERVICE.wallClockTime())) {
        assertEquals(expectedValue, d0.getValue());
        c++;
      }
      if (d1 != null && !d1.isExpired(TIME_SERVICE.wallClockTime())) {
        assertEquals(expectedValue, d1.getValue());
        c++;
      }
      if (d2 != null && !d2.isExpired(TIME_SERVICE.wallClockTime())) {
        assertEquals(expectedValue, d2.getValue());
        c++;
      }
      assertEquals(1, c);

      // look at them also via cache API
      assertEquals(expectedValue, cache(0).get(key));
      assertEquals(expectedValue, cache(1).get(key));
      assertEquals(expectedValue, cache(2).get(key));
    }
  }