package org.opendaylight.genius.idmanager.test;
import static java.util.Comparator.comparing;
+import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.opendaylight.genius.idmanager.IdUtils.nullToEmpty;
import com.google.common.base.Optional;
-
+import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashSet;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
-
import javax.inject.Inject;
-
+import junit.framework.AssertionFailedError;
import org.junit.Before;
import org.junit.ComparisonFailure;
-import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
import org.opendaylight.genius.datastoreutils.testutils.TestableDataTreeChangeListenerModule;
import org.opendaylight.genius.idmanager.IdUtils;
import org.opendaylight.infrautils.inject.guice.testutils.GuiceRule;
+import org.opendaylight.infrautils.testutils.LogCaptureRule;
import org.opendaylight.infrautils.testutils.LogRule;
+import org.opendaylight.infrautils.utils.concurrent.Executors;
import org.opendaylight.mdsal.binding.testutils.AssertDataObjects;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
public class IdManagerTest {
+ private static final Logger LOG = LoggerFactory.getLogger(IdManagerTest.class);
+
private static final String TEST_KEY1 = "test-key1";
private static final String TEST_KEY2 = "test-key2";
private static final String ID_POOL_NAME = "test-pool";
private static final long ID_LOW = 0L;
private static final long ID_HIGH = 100L;
+ // public static @ClassRule RunUntilFailureClassRule classRepeater = new RunUntilFailureClassRule();
+ // public @Rule RunUntilFailureRule repeater = new RunUntilFailureRule(classRepeater);
+
public @Rule LogRule logRule = new LogRule();
+ public @Rule LogCaptureRule logCaptureRule = new LogCaptureRule();
+
public @Rule MethodRule guice = new GuiceRule(IdManagerTestModule.class,
TestableDataTreeChangeListenerModule.class, JobCoordinatorTestModule.class);
asyncEventsWaiter.awaitEventsConsumption();
String localPoolName = idUtils.getLocalPoolName(ID_POOL_NAME);
- IdPool parentIdPool = new IdPoolBuilder().setPoolName(ID_POOL_NAME).setKey(new IdPoolKey(ID_POOL_NAME))
+ IdPool parentIdPool = new IdPoolBuilder().setPoolName(ID_POOL_NAME).withKey(new IdPoolKey(ID_POOL_NAME))
+ .setAvailableIdsHolder(createAvailableIdHolder(ID_LOW, ID_HIGH, ID_HIGH + 1))
.setReleasedIdsHolder(createReleaseIdHolder(Arrays.asList(1L, 2L, 3L))).build();
- IdPool childPool = new IdPoolBuilder().setPoolName(localPoolName).setKey(new IdPoolKey(localPoolName))
+ IdPool childPool = new IdPoolBuilder().setPoolName(localPoolName).withKey(new IdPoolKey(localPoolName))
.setAvailableIdsHolder(createAvailableIdHolder(0L, 9L, 10L)).build();
WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(ID_POOL_NAME), parentIdPool);
Optional<IdPool> actualIdPoolChild = singleTxdataBroker.syncReadOptional(LogicalDatastoreType.CONFIGURATION,
InstanceIdentifier.builder(IdPools.class)
.child(IdPool.class, new IdPoolKey(idUtils.getLocalPoolName(ID_POOL_NAME))).build());
- assertEquals(false, actualIdPoolParent.isPresent());
- assertEquals(false, actualIdPoolChild.isPresent());
+ assertFalse(actualIdPoolParent.isPresent());
+ assertFalse(actualIdPoolChild.isPresent());
}
@Test
- public void testMultithreadedIdAllocationFromAvailableIds() throws Exception {
+ @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
+ public void testMultithreadedIdAllocationFromAvailableIds() throws Throwable {
CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
.setPoolName(ID_POOL_NAME).build();
idManagerService.createIdPool(createIdPoolInput);
}
@Test
- public void testMultithreadedIdAllocationFromReleaseIds() throws Exception {
+ @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
+ public void testMultithreadedIdAllocationFromReleaseIds() throws Throwable {
CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
.setPoolName(ID_POOL_NAME).build();
AllocateIdInput allocateIdInput = new AllocateIdInputBuilder().setIdKey(TEST_KEY1).setPoolName(ID_POOL_NAME)
coordinatorEventsWaiter.awaitEventsConsumption();
String localPoolName = idUtils.getLocalPoolName(ID_POOL_NAME);
- IdPool parentIdPool = new IdPoolBuilder().setPoolName(ID_POOL_NAME).setKey(new IdPoolKey(ID_POOL_NAME))
- .setReleasedIdsHolder(createReleaseIdHolder(Arrays.asList(1L, 2L, 3L))).build();
- IdPool childPool = new IdPoolBuilder().setPoolName(localPoolName).setKey(new IdPoolKey(localPoolName))
+ IdPool parentIdPool = new IdPoolBuilder().setPoolName(ID_POOL_NAME).withKey(new IdPoolKey(ID_POOL_NAME))
+ .setReleasedIdsHolder(createReleaseIdHolder(Collections.emptyList())).build();
+ IdPool childPool = new IdPoolBuilder().setPoolName(localPoolName).withKey(new IdPoolKey(localPoolName))
+ .setReleasedIdsHolder(createReleaseIdHolder(Arrays.asList(1L, 2L, 3L)))
.setAvailableIdsHolder(createAvailableIdHolder(0L, 9L, 10L)).build();
WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(ID_POOL_NAME), parentIdPool);
}
@Test
- @Ignore // TODO make less brittle and completely reliable, see https://jira.opendaylight.org/browse/GENIUS-105
- public void testMultithreadedIdAllocationForSameKeyFromAvailableIds() throws Exception {
+ @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
+ public void testMultithreadedIdAllocationForSameKeyFromAvailableIds() throws Throwable {
CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
.setPoolName(ID_POOL_NAME).build();
idManagerService.createIdPool(createIdPoolInput);
}
@Test
- @Ignore
- public void testMultithreadedIdAllocationForSameKeyFromReleasedIds() throws Exception {
+ @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
+ public void testMultithreadedIdAllocationForSameKeyFromReleasedIds() throws Throwable {
CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
.setPoolName(ID_POOL_NAME).build();
AllocateIdInput allocateIdInput = new AllocateIdInputBuilder().setIdKey(TEST_KEY2).setPoolName(ID_POOL_NAME)
asyncEventsWaiter.awaitEventsConsumption();
String localPoolName = idUtils.getLocalPoolName(ID_POOL_NAME);
- IdPool parentIdPool = new IdPoolBuilder().setPoolName(ID_POOL_NAME).setKey(new IdPoolKey(ID_POOL_NAME))
- .setReleasedIdsHolder(createReleaseIdHolder(Arrays.asList(1L, 2L, 3L))).build();
- IdPool childPool = new IdPoolBuilder().setPoolName(localPoolName).setKey(new IdPoolKey(localPoolName))
+ IdPool parentIdPool = new IdPoolBuilder().setPoolName(ID_POOL_NAME).withKey(new IdPoolKey(ID_POOL_NAME))
+ .setAvailableIdsHolder(createAvailableIdHolder(ID_LOW, ID_HIGH, ID_HIGH + 1))
+ .setReleasedIdsHolder(createReleaseIdHolder(Collections.emptyList())).build();
+ IdPool childPool = new IdPoolBuilder().setPoolName(localPoolName).withKey(new IdPoolKey(localPoolName))
+ .setReleasedIdsHolder(createReleaseIdHolder(Arrays.asList(1L, 2L, 3L)))
.setAvailableIdsHolder(createAvailableIdHolder(0L, 9L, 10L)).build();
WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(ID_POOL_NAME), parentIdPool);
ExpectedAllocateIdFromReleasedId.idPoolChild());
}
- private void requestIdsConcurrently(boolean isSameKey) throws InterruptedException {
+ @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
+ private void requestIdsConcurrently(boolean isSameKey) throws Throwable {
int numberOfTasks = 3;
CountDownLatch latch = new CountDownLatch(numberOfTasks);
- Set<Long> idSet = new HashSet<>();
- ExecutorService executor = Executors.newCachedThreadPool();
+ Set<Long> idSet = Sets.newConcurrentHashSet();
+ ExecutorService executor = Executors.newCachedThreadPool("requestIdsConcurrently()", LOG);
+ AtomicReference<Throwable> exceptionInExecutorAtomic = new AtomicReference<>();
for (int i = 0; i < numberOfTasks; i++) {
final String idKey;
if (isSameKey) {
idKey = TEST_KEY1 + i;
}
executor.execute(() -> {
+ // Any exception thrown inside this background thread will not cause the test to fail
+ // so you cannot use assert* here but must set the exceptionInExecutor which is checked after
Future<RpcResult<AllocateIdOutput>> result;
result = idManagerService.allocateId(
new AllocateIdInputBuilder().setPoolName(ID_POOL_NAME).setIdKey(idKey).build());
if (result.get().isSuccessful()) {
Long idValue = result.get().getResult().getIdValue();
idSet.add(idValue);
- assertTrue(idValue <= ID_LOW + BLOCK_SIZE);
+ if (idValue > ID_LOW + BLOCK_SIZE) {
+ exceptionInExecutorAtomic.set(new AssertionFailedError("idValue <= ID_LOW + BLOCK_SIZE"));
+ }
} else {
RpcError error = result.get().getErrors().iterator().next();
- assertTrue(error.getCause().getMessage().contains("Ids exhausted for pool : " + ID_POOL_NAME));
+ if (!error.getCause().getMessage().contains("Ids exhausted for pool : " + ID_POOL_NAME)) {
+ exceptionInExecutorAtomic.set(error.getCause());
+ }
}
- } catch (ExecutionException | InterruptedException e) {
- assertTrue(e.getCause().getMessage(), false);
+ } catch (InterruptedException | ExecutionException e) {
+ exceptionInExecutorAtomic.set(e);
} finally {
latch.countDown();
}
});
}
- latch.await();
+ if (!latch.await(13, SECONDS)) {
+ fail("latch.await(13, SECONDS) timed out :(");
+ }
+ Throwable exceptionInExecutor = exceptionInExecutorAtomic.get();
+ if (exceptionInExecutor != null) {
+ throw exceptionInExecutor;
+ }
if (isSameKey) {
- assertTrue(idSet.size() == 1);
+ assertEquals(1, idSet.size());
} else {
- assertTrue(idSet.size() == numberOfTasks);
+ assertEquals(numberOfTasks, idSet.size());
}
}
private InstanceIdentifier<IdPool> getIdPoolIdentifier(String poolName) {
InstanceIdentifier.InstanceIdentifierBuilder<IdPool> idBuilder =
InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(poolName));
- InstanceIdentifier<IdPool> id = idBuilder.build();
- return id;
+ return idBuilder.build();
}
private ReleasedIdsHolder createReleaseIdHolder(List<Long> delayedIds) {
delayedIdEntries.add(new DelayedIdEntriesBuilder().setId(id).setReadyTimeSec(0L).build());
}
return new ReleasedIdsHolderBuilder().setDelayedIdEntries(delayedIdEntries)
- .setAvailableIdCount(Long.valueOf(delayedIds.size())).build();
+ .setAvailableIdCount((long) delayedIds.size()).build();
}
private AvailableIdsHolder createAvailableIdHolder(long start, long end, long cursor) {
private IdPool getUpdatedActualParentPool() throws ReadFailedException {
IdPool idPoolParentFromDS = singleTxdataBroker.syncRead(LogicalDatastoreType.CONFIGURATION,
InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(ID_POOL_NAME)).build());
- List<ChildPools> childPool = idPoolParentFromDS.getChildPools();
+ List<ChildPools> childPool = nullToEmpty(idPoolParentFromDS.getChildPools());
List<ChildPools> updatedChildPool = childPool.stream()
.map(child -> new ChildPoolsBuilder(child).setLastAccessTime(0L).build()).collect(Collectors.toList());
List<IdEntries> idEntries = idPoolParentFromDS.getIdEntries();
.collect(Collectors.toList());
idPoolBuilder.setIdEntries(sortedIdEntries);
}
- IdPool actualIdPoolParent = idPoolBuilder.setChildPools(updatedChildPool).build();
- return actualIdPoolParent;
+ return idPoolBuilder.setChildPools(updatedChildPool).build();
}
}