+/*
+ * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
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.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.when;
+import static org.junit.Assert.fail;
+import static org.opendaylight.genius.idmanager.IdUtils.nullToEmpty;
-import java.net.InetAddress;
+import com.google.common.base.Optional;
+import com.google.common.collect.Sets;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
-import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
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.Rule;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
+import org.junit.rules.MethodRule;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.genius.idmanager.IdManager;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.datastoreutils.testutils.AsyncEventsWaiter;
+import org.opendaylight.genius.datastoreutils.testutils.JobCoordinatorEventsWaiter;
+import org.opendaylight.genius.datastoreutils.testutils.JobCoordinatorTestModule;
+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.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdPools;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolderBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPools;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPoolsBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPoolsKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntries;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntriesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntriesKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolderBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntries;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntriesBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInput;
-import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Optional;
-import com.google.common.net.InetAddresses;
-import com.google.common.util.concurrent.Futures;
-
-@RunWith(MockitoJUnitRunner.class)
public class IdManagerTest {
+
private static final Logger LOG = LoggerFactory.getLogger(IdManagerTest.class);
- private static int BLADE_ID;
- static {
- try {
- BLADE_ID = InetAddresses.coerceToInteger(InetAddress.getLocalHost());
- } catch (Exception e) {
- LOG.error("IdManager - Exception - {}", e.getMessage());
- }
- }
- Map<InstanceIdentifier<?>,DataObject> configDataStore = new HashMap<>();
- @Mock DataBroker dataBroker;
- @Mock ReadOnlyTransaction mockReadTx;
- @Mock WriteTransaction mockWriteTx;
- @Mock LockManagerService lockManager;
- Future<RpcResult<Void>> rpcResult;
- IdManager idManager;
- IdPool globalIdPool;
- InstanceIdentifier<IdPool> identifier;
- InstanceIdentifier<IdPool> childIdentifier;
- InstanceIdentifier<ChildPools> childPoolIdentifier;
- String globalPoolName = "test-pool";
- String localPoolName = new StringBuilder(globalPoolName).append(".").append(BLADE_ID).toString();
- String idKey = "test-key1";
- int idStart = 100;
- int idEnd = 200;
- int blockSize = 2;
- String idKey2 = "test-key2";
- int idValue = 25;
+ 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 int BLOCK_SIZE = 10;
+ private static final long ID_LOW = 0L;
+ private static final long ID_HIGH = 100L;
- @Before
- public void setUp() throws Exception {
+ // public static @ClassRule RunUntilFailureClassRule classRepeater = new RunUntilFailureClassRule();
+ // public @Rule RunUntilFailureRule repeater = new RunUntilFailureRule(classRepeater);
- idManager = new IdManager(dataBroker);
- idManager.setLockManager(lockManager);
- setupMocks();
- }
+ public @Rule LogRule logRule = new LogRule();
+ public @Rule LogCaptureRule logCaptureRule = new LogCaptureRule();
+
+ public @Rule MethodRule guice = new GuiceRule(IdManagerTestModule.class,
+ TestableDataTreeChangeListenerModule.class, JobCoordinatorTestModule.class);
+
+ private @Inject IdManagerService idManagerService;
+ private @Inject DataBroker dataBroker;
+ private @Inject AsyncEventsWaiter asyncEventsWaiter;
+ private @Inject JobCoordinatorEventsWaiter coordinatorEventsWaiter;
+ private @Inject IdUtils idUtils;
+
+ private SingleTransactionDataBroker singleTxdataBroker;
- private void setupMocks() {
- globalIdPool = buildGlobalIdPool(globalPoolName, idStart, idEnd, blockSize, buildChildPool(localPoolName)).build();
- identifier = buildInstanceIdentifier(globalPoolName);
- childIdentifier = buildInstanceIdentifier(localPoolName);
- childPoolIdentifier = buildChildPoolInstanceIdentifier(globalPoolName, localPoolName);
- when(dataBroker.newReadOnlyTransaction()).thenReturn(mockReadTx);
- when(dataBroker.newWriteOnlyTransaction()).thenReturn(mockWriteTx);
- when(lockManager.lock(any(LockInput.class))).thenReturn(Futures.immediateFuture(RpcResultBuilder.<Void>success().build()));
- when(lockManager.unlock(any(UnlockInput.class))).thenReturn(Futures.immediateFuture(RpcResultBuilder.<Void>success().build()));
- doReturn(Futures.immediateCheckedFuture(null)).when(mockWriteTx).submit();
- doReturn(Futures.immediateCheckedFuture(null)).when(mockReadTx).read(eq(LogicalDatastoreType.OPERATIONAL), any(InstanceIdentifier.class));
+ @Before
+ public void before() {
+ singleTxdataBroker = new SingleTransactionDataBroker(dataBroker);
}
@Test
- public void testCreateIdPool() throws Exception
- {
- CreateIdPoolInput createPoolTest = buildCreateIdPool(globalPoolName, idStart, idEnd);
- doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, identifier);
- doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, childIdentifier);
- Future<RpcResult<Void>> result = idManager.createIdPool(createPoolTest);
- DataObject dataObject;
- IdPool pool;
- assertTrue(result.get().isSuccessful());
- assertEquals(0,configDataStore.size());
- dataObject = configDataStore.get(childIdentifier);
- if (dataObject instanceof IdPool) {
- pool = (IdPool) dataObject;
- assertEquals(localPoolName, pool.getPoolName());
- assertEquals(createPoolTest.getPoolName(), pool.getParentPoolName());
- assertEquals(null, pool.getAvailableIdsHolder());
- assertEquals(30, pool.getReleasedIdsHolder().getDelayedTimeSec().longValue());
- assertEquals(0, pool.getReleasedIdsHolder().getAvailableIdCount().longValue());
- assertEquals(blockSize, pool.getBlockSize().longValue());
- }
- dataObject = configDataStore.get(identifier);
- if (dataObject instanceof IdPool) {
- pool = (IdPool) dataObject;
- assertEquals(createPoolTest.getPoolName(), pool.getPoolName());
- assertEquals(0, pool.getReleasedIdsHolder().getDelayedTimeSec().longValue());
- assertEquals(0, pool.getReleasedIdsHolder().getAvailableIdCount().longValue());
- assertEquals(createPoolTest.getLow(), pool.getAvailableIdsHolder().getStart());
- assertEquals(createPoolTest.getHigh(), pool.getAvailableIdsHolder().getEnd());
- assertEquals(createPoolTest.getLow() - 1, pool.getAvailableIdsHolder().getCursor().intValue());
- assertEquals(blockSize, pool.getBlockSize().longValue());
- }
- dataObject = configDataStore.get(childPoolIdentifier);
- if (dataObject instanceof ChildPools) {
- ChildPools childPool = (ChildPools) dataObject;
- assertEquals(localPoolName, childPool.getChildPoolName());
- }
+ public void testCreateIdPool() throws Exception {
+ CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
+ .setPoolName(ID_POOL_NAME).build();
+ assertTrue(idManagerService.createIdPool(createIdPoolInput).get().isSuccessful());
+ coordinatorEventsWaiter.awaitEventsConsumption();
+ validateIdPools(ExpectedCreateIdPoolObjects.idPoolCreateParent(),
+ ExpectedCreateIdPoolObjects.idPoolCreateChild());
}
@Test
- public void testAllocateId() throws Exception
- {
- AllocateIdInput allocateIdInput = buildAllocateId(globalPoolName, idKey);
- List<IdEntries> idEntries = new ArrayList<IdEntries>();
- idEntries.add(buildIdEntry(idKey2, idValue));
- Optional<IdPool> expectedLocalPool = Optional.of(buildLocalIdPool(blockSize, localPoolName, globalPoolName).build());
- IdPool globalIdPool = buildGlobalIdPool(globalPoolName, idStart, idEnd, blockSize, buildChildPool(localPoolName)).setIdEntries(idEntries).build();
- Optional<IdPool> expectedGlobalPool = Optional.of(globalIdPool);
- doReturn(Futures.immediateCheckedFuture(expectedGlobalPool)).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, identifier);
- doReturn(Futures.immediateCheckedFuture(expectedLocalPool)).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, childIdentifier);
- InstanceIdentifier<IdEntries> idEntriesIdentifier = buildIdEntriesIdentifier(idKey);
- doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, idEntriesIdentifier);
- InstanceIdentifier<AvailableIdsHolder> availableIdsIdentifier = buildAvailbaleIdsIdentifier(globalPoolName);
-
- Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(allocateIdInput);
- assertTrue(result.get().isSuccessful());
- assertEquals(0,configDataStore.size());
- DataObject dataObject = configDataStore.get(childIdentifier);
- if (dataObject instanceof IdPool) {
- IdPool pool = (IdPool) dataObject;
- assertEquals(localPoolName, pool.getPoolName());
- assertEquals(idStart, pool.getAvailableIdsHolder().getStart().intValue());
- assertEquals(idStart + blockSize - 1 , pool.getAvailableIdsHolder().getEnd().intValue());
- assertEquals(idStart, pool.getAvailableIdsHolder().getCursor().intValue());
- }
- dataObject = configDataStore.get(identifier);
- if (dataObject instanceof IdPool) {
- IdPool parentPool = (IdPool) dataObject;
- assertEquals(2, parentPool.getIdEntries().size());
- }
- dataObject = configDataStore.get(availableIdsIdentifier);
- if (dataObject instanceof AvailableIdsHolder) {
- AvailableIdsHolder availableIds = (AvailableIdsHolder) dataObject;
- assertEquals(idEnd, availableIds.getEnd().intValue());
- assertEquals(idStart, availableIds.getStart().intValue());
- assertEquals(idStart + blockSize - 1, availableIds.getCursor().intValue());
- }
+ public void testAllocateId() throws Exception {
+ 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)
+ .build();
+ idManagerService.createIdPool(createIdPoolInput);
+ assertEquals(idManagerService.allocateId(allocateIdInput).get().getResult().getIdValue().longValue(), 0L);
+ coordinatorEventsWaiter.awaitEventsConsumption();
+
+ validateIdPools(ExpectedAllocateIdObjects.idPoolParent(), ExpectedAllocateIdObjects.idPoolChild());
}
@Test
public void testReleaseId() throws Exception {
- ReleaseIdInput releaseIdInput = createReleaseIdInput(globalPoolName, idKey);
- List<IdEntries> idEntries = new ArrayList<IdEntries>();
- idEntries.add(buildIdEntry(idKey, idValue));
- Optional<IdPool> expectedLocalPool = Optional.of(buildLocalIdPool(blockSize, localPoolName, globalPoolName).build());
- IdPool globalIdPool = buildGlobalIdPool(globalPoolName, idStart, idEnd, blockSize, buildChildPool(localPoolName)).setIdEntries(idEntries).build();
- Optional<IdPool> expectedGlobalPool = Optional.of(globalIdPool);
- doReturn(Futures.immediateCheckedFuture(expectedGlobalPool)).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, identifier);
- doReturn(Futures.immediateCheckedFuture(expectedLocalPool)).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, childIdentifier);
- InstanceIdentifier<IdEntries> idEntriesIdentifier = buildIdEntriesIdentifier(idKey);
- Optional<IdEntries> expectedIdEntry = Optional.of(buildIdEntry(idKey, idValue));
- doReturn(Futures.immediateCheckedFuture(expectedIdEntry)).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, idEntriesIdentifier);
- Future<RpcResult<Void>> result = idManager.releaseId(releaseIdInput);
- assertTrue(result.get().isSuccessful());
- assertEquals(0, configDataStore.size());
- DataObject idPoolVal = configDataStore.get(childIdentifier);
- if (idPoolVal instanceof IdPool) {
- IdPool pool = (IdPool) idPoolVal;
- assertEquals(0, pool.getReleasedIdsHolder().getAvailableIdCount().intValue());
- assertEquals(idValue, pool.getReleasedIdsHolder().getDelayedIdEntries().get(0).getId().intValue());
- }
- idPoolVal = configDataStore.get(identifier);
- if (idPoolVal instanceof IdPool) {
- IdPool parentPool = (IdPool) idPoolVal;
- assertEquals(0, parentPool.getIdEntries().size());
- }
- }
+ 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)
+ .build();
+ ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setIdKey(TEST_KEY1).setPoolName(ID_POOL_NAME)
+ .build();
+ idManagerService.createIdPool(createIdPoolInput);
+ idManagerService.allocateId(allocateIdInput);
+ assertTrue(idManagerService.releaseId(releaseIdInput).get().isSuccessful());
+ coordinatorEventsWaiter.awaitEventsConsumption();
- @Test
- public void testCleanupReleasedIds() throws Exception {
- AllocateIdInput allocateIdInput = buildAllocateId(globalPoolName, idKey2);
- Optional<ReleasedIdsHolder> expected = Optional.of(createReleasedIdsHolder(0, null, 0));
- long[] excessIds = new long[] { 1, 2, 3, 4, 5 };
- List<IdEntries> idEntries = new ArrayList<IdEntries>();
- idEntries.add(buildIdEntry(idKey2, idValue));
- ReleasedIdsHolder excessReleasedIds = createReleasedIdsHolder(0, buildDelayedIdEntries(excessIds), (long) 30);
- Optional<IdPool> expectedLocalPool = Optional.of(buildLocalIdPool(blockSize, localPoolName, globalPoolName)
- .setReleasedIdsHolder(excessReleasedIds)
- .build());
- InstanceIdentifier<ReleasedIdsHolder> releaseIdsIdentifier = buildReleaseIdsIdentifier(globalPoolName);
- IdPool globalIdPool = buildGlobalIdPool(globalPoolName, idStart, idEnd, blockSize, buildChildPool(localPoolName)).setIdEntries(idEntries).build();
- Optional<IdPool> expectedGlobalPool = Optional.of(globalIdPool);
- doReturn(Futures.immediateCheckedFuture(expectedGlobalPool)).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, identifier);
- doReturn(Futures.immediateCheckedFuture(expected)).when(mockReadTx)
- .read(LogicalDatastoreType.CONFIGURATION, releaseIdsIdentifier);
- doReturn(Futures.immediateCheckedFuture(expectedLocalPool)).when(
- mockReadTx).read(LogicalDatastoreType.CONFIGURATION,
- childIdentifier);
- InstanceIdentifier<IdEntries> idEntriesIdentifier = buildIdEntriesIdentifier(idKey2);
- doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(
- mockReadTx).read(LogicalDatastoreType.CONFIGURATION,
- idEntriesIdentifier);
-
- Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(allocateIdInput);
- assertTrue(result.get().isSuccessful());
- assertEquals(0, configDataStore.size());
- DataObject dataObject = configDataStore.get(childIdentifier);
- if (dataObject instanceof IdPool) {
- IdPool pool = (IdPool) dataObject;
- assertEquals(localPoolName, pool.getPoolName());
- assertEquals(excessIds.length - 3, pool.getReleasedIdsHolder().getAvailableIdCount().intValue());
- }
- dataObject = configDataStore.get(identifier);
- if (dataObject instanceof IdPool) {
- IdPool parentPool = (IdPool) dataObject;
- assertEquals(2, parentPool.getIdEntries().size());
- }
- dataObject = configDataStore.get(releaseIdsIdentifier);
- if (dataObject instanceof ReleasedIdsHolder) {
- ReleasedIdsHolder releasedIds = (ReleasedIdsHolder) dataObject;
- assertEquals(2, releasedIds.getAvailableIdCount().intValue());
- assertEquals(2, releasedIds.getDelayedIdEntries().size());
- }
+ validateIdPools(ExpectedReleaseIdObjects.idPoolParent(), ExpectedReleaseIdObjects.idPoolChild());
}
@Test
public void testAllocateIdBlockFromReleasedIds() throws Exception {
- AllocateIdInput allocateIdInput = buildAllocateId(globalPoolName, globalPoolName);
- List<DelayedIdEntries> delayedIdEntries = buildDelayedIdEntries(new long[] {1, 2, 3});
- ReleasedIdsHolder expectedReleasedIds = createReleasedIdsHolder(3, delayedIdEntries , 0);
- IdPool globalIdPool = buildGlobalIdPool(globalPoolName, idStart, idEnd, blockSize, buildChildPool(localPoolName)).setReleasedIdsHolder(expectedReleasedIds).build();
- Optional<IdPool> expected = Optional.of(globalIdPool);
- Optional<IdPool> expectedLocalPool = Optional.of(buildLocalIdPool(blockSize, localPoolName, globalPoolName).build());
- doReturn(Futures.immediateCheckedFuture(expected)).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, identifier);
- doReturn(Futures.immediateCheckedFuture(expectedLocalPool)).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, childIdentifier);
- InstanceIdentifier<IdEntries> idEntriesIdentifier = buildIdEntriesIdentifier(globalPoolName);
- doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, idEntriesIdentifier);
- InstanceIdentifier<ReleasedIdsHolder> releaseIdsIdentifier = buildReleaseIdsIdentifier(globalPoolName);
-
- Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(allocateIdInput);
- assertTrue(result.get().isSuccessful());
- assertEquals(0,configDataStore.size());
- DataObject dataObject = configDataStore.get(childIdentifier);
- if (dataObject instanceof IdPool) {
- IdPool pool = (IdPool) dataObject;
- assertEquals(localPoolName, pool.getPoolName());
- assertEquals(1, pool.getReleasedIdsHolder().getDelayedIdEntries().size());
- assertEquals(1, pool.getReleasedIdsHolder().getAvailableIdCount().intValue());
- }
- dataObject = configDataStore.get(identifier);
- if (dataObject instanceof IdPool) {
- IdPool parentPool = (IdPool) dataObject;
- assertEquals(1, parentPool.getIdEntries().size());
- }
- dataObject = configDataStore.get(releaseIdsIdentifier);
- if (dataObject instanceof ReleasedIdsHolder) {
- ReleasedIdsHolder releasedIds = (ReleasedIdsHolder) dataObject;
- assertEquals(1, releasedIds.getAvailableIdCount().intValue());
- assertEquals(1, releasedIds.getDelayedIdEntries().size());
- }
+ 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)
+ .build();
+ idManagerService.createIdPool(createIdPoolInput);
+ idManagerService.allocateId(allocateIdInput);
+ coordinatorEventsWaiter.awaitEventsConsumption();
+ asyncEventsWaiter.awaitEventsConsumption();
+
+ String localPoolName = idUtils.getLocalPoolName(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).withKey(new IdPoolKey(localPoolName))
+ .setAvailableIdsHolder(createAvailableIdHolder(0L, 9L, 10L)).build();
+ WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
+ tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(ID_POOL_NAME), parentIdPool);
+ tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(localPoolName), childPool);
+ tx.submit().get();
+
+ AllocateIdInput allocateIdInput2 = new AllocateIdInputBuilder().setIdKey(TEST_KEY1).setPoolName(ID_POOL_NAME)
+ .build();
+ assertEquals(idManagerService.allocateId(allocateIdInput2).get().getResult().getIdValue().longValue(), 1L);
+
+ coordinatorEventsWaiter.awaitEventsConsumption();
+ validateIdPools(ExpectedAllocateIdFromReleasedId.idPoolParent(),
+ ExpectedAllocateIdFromReleasedId.idPoolChild());
}
@Test
public void testDeletePool() throws Exception {
- IdPool globalIdPool = buildGlobalIdPool(globalPoolName, idStart, idEnd, blockSize, buildChildPool(localPoolName)).build();
- Optional<IdPool> expected = Optional.of(globalIdPool);
- Optional<IdPool> expectedLocalPool = Optional.of(buildLocalIdPool(blockSize, localPoolName, globalPoolName).build());
- doReturn(Futures.immediateCheckedFuture(expected)).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, identifier);
- doReturn(Futures.immediateCheckedFuture(expectedLocalPool)).when(mockReadTx).read(
- LogicalDatastoreType.CONFIGURATION, childIdentifier);
- DeleteIdPoolInput deleteIdPoolInput = createDeleteIdPoolInput(globalPoolName);
- configDataStore.put(childIdentifier, null);
- configDataStore.put(identifier, null);
- Future<RpcResult<Void>> result = idManager.deleteIdPool(deleteIdPoolInput);
- assertTrue(result.get().isSuccessful());
- assertEquals(2, configDataStore.size());
- }
-
- private InstanceIdentifier<ReleasedIdsHolder> buildReleaseIdsIdentifier(
- String poolName) {
- InstanceIdentifier<ReleasedIdsHolder> releasedIds = InstanceIdentifier
- .builder(IdPools.class).child(IdPool.class,
- new IdPoolKey(poolName)).child(ReleasedIdsHolder.class).build();
- return releasedIds;
+ CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
+ .setPoolName(ID_POOL_NAME).build();
+ idManagerService.createIdPool(createIdPoolInput);
+ DeleteIdPoolInput deleteIdPoolInput = new DeleteIdPoolInputBuilder().setPoolName(ID_POOL_NAME).build();
+ assertTrue(idManagerService.deleteIdPool(deleteIdPoolInput).get().isSuccessful());
+ coordinatorEventsWaiter.awaitEventsConsumption();
+ Optional<IdPool> actualIdPoolParent = singleTxdataBroker.syncReadOptional(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(ID_POOL_NAME)).build());
+ Optional<IdPool> actualIdPoolChild = singleTxdataBroker.syncReadOptional(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.builder(IdPools.class)
+ .child(IdPool.class, new IdPoolKey(idUtils.getLocalPoolName(ID_POOL_NAME))).build());
+ assertFalse(actualIdPoolParent.isPresent());
+ assertFalse(actualIdPoolChild.isPresent());
}
- private InstanceIdentifier<AvailableIdsHolder> buildAvailbaleIdsIdentifier(
- String poolName) {
- InstanceIdentifier<AvailableIdsHolder> availableIds = InstanceIdentifier
- .builder(IdPools.class).child(IdPool.class,
- new IdPoolKey(poolName)).child(AvailableIdsHolder.class).build();
- return availableIds;
- }
-
- private InstanceIdentifier<ChildPools> buildChildPoolInstanceIdentifier(String poolName, String childPoolName) {
- InstanceIdentifier<ChildPools> childPool = InstanceIdentifier
- .builder(IdPools.class).child(IdPool.class,
- new IdPoolKey(poolName)).child(ChildPools.class, new ChildPoolsKey(childPoolName)).build();
- return childPool;
- }
-
- private ReleaseIdInput createReleaseIdInput(String poolName, String idKey) {
- return new ReleaseIdInputBuilder().setIdKey(idKey).setPoolName(poolName).build();
- }
-
- private IdEntries buildIdEntry(String idKey, long idValue) {
- return new IdEntriesBuilder().setIdKey(idKey).setIdValue(idValue).build();
- }
-
- private InstanceIdentifier<IdEntries> buildIdEntriesIdentifier(String idKey) {
- InstanceIdentifier.InstanceIdentifierBuilder<IdEntries> idEntriesBuilder = identifier
- .builder().child(IdEntries.class, new IdEntriesKey(idKey));
- InstanceIdentifier<IdEntries> idEntry = idEntriesBuilder.build();
- return idEntry;
+ @Test
+ @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);
+ requestIdsConcurrently(false);
+ coordinatorEventsWaiter.awaitEventsConsumption();
+ IdPool actualIdPoolChild = getUpdatedActualChildPool();
+ IdPool actualIdPoolParent = getUpdatedActualParentPool();
+ // Cannot compare the idEntries since we cannot guarantee which idKey gets what value.
+ // However the allocated id values uniqueness is verified in requestIdsConcurrently method.
+ AssertDataObjects.assertEqualBeans(
+ ExpectedAllocateIdMultipleRequestsFromAvailableIds.idPoolParent().getAvailableIdsHolder(),
+ actualIdPoolParent.getAvailableIdsHolder());
+ AssertDataObjects.assertEqualBeans(ExpectedAllocateIdMultipleRequestsFromAvailableIds.idPoolChild(),
+ actualIdPoolChild);
}
- private CreateIdPoolInput buildCreateIdPool(String poolName, long low, long high) {
- CreateIdPoolInput createPool = new CreateIdPoolInputBuilder().setPoolName(poolName)
- .setLow(low)
- .setHigh(high)
+ @Test
+ @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)
.build();
- return createPool;
+ idManagerService.createIdPool(createIdPoolInput);
+ idManagerService.allocateId(allocateIdInput);
+ // Should wait for all job to complete.
+ coordinatorEventsWaiter.awaitEventsConsumption();
+
+ String localPoolName = idUtils.getLocalPoolName(ID_POOL_NAME);
+ 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);
+ tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(localPoolName), childPool);
+ tx.submit().get();
+ // Wait for the changes to be available on the caches.
+ asyncEventsWaiter.awaitEventsConsumption();
+ requestIdsConcurrently(false);
+ coordinatorEventsWaiter.awaitEventsConsumption();
+ asyncEventsWaiter.awaitEventsConsumption();
+
+ IdPool actualIdPoolChild = getUpdatedActualChildPool();
+ IdPool actualIdPoolParent = getUpdatedActualParentPool();
+ // Cannot compare the idEntries since we cannot guarantee which idKey gets what value.
+ // However the allocated id values uniqueness is verified in requestIdsConcurrently method.
+ AssertDataObjects.assertEqualBeans(
+ ExpectedAllocateIdMultipleRequestsFromReleaseIds.idPoolParent().getReleasedIdsHolder(),
+ actualIdPoolParent.getReleasedIdsHolder());
+ AssertDataObjects.assertEqualBeans(ExpectedAllocateIdMultipleRequestsFromReleaseIds.idPoolChild(),
+ actualIdPoolChild);
}
- private IdPoolBuilder buildGlobalIdPool(String poolName, long idStart, long poolSize, int blockSize, List<ChildPools> childPools) {
- AvailableIdsHolder availableIdsHolder = createAvailableIdsHolder(idStart, poolSize, idStart - 1);
- ReleasedIdsHolder releasedIdsHolder = createReleasedIdsHolder(0, null, 0);
- return new IdPoolBuilder().setKey(new IdPoolKey(poolName))
- .setPoolName(poolName)
- .setBlockSize(blockSize)
- .setChildPools(childPools)
- .setAvailableIdsHolder(availableIdsHolder)
- .setReleasedIdsHolder(releasedIdsHolder);
+ @Test
+ @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);
+ requestIdsConcurrently(true);
+ coordinatorEventsWaiter.awaitEventsConsumption();
+
+ validateIdPools(ExpectedAllocateIdObjects.idPoolParent(), ExpectedAllocateIdObjects.idPoolChild());
}
- private IdPoolBuilder buildLocalIdPool(int blockSize, String localPoolName, String parentPoolName) {
- ReleasedIdsHolder releasedIdsHolder = createReleasedIdsHolder(0, null, (long) 30);
- return new IdPoolBuilder().setBlockSize(blockSize)
- .setKey(new IdPoolKey(localPoolName))
- .setParentPoolName(parentPoolName)
- .setReleasedIdsHolder(releasedIdsHolder);
+ @Test
+ @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)
+ .build();
+ idManagerService.createIdPool(createIdPoolInput);
+ idManagerService.allocateId(allocateIdInput);
+ coordinatorEventsWaiter.awaitEventsConsumption();
+ asyncEventsWaiter.awaitEventsConsumption();
+
+ String localPoolName = idUtils.getLocalPoolName(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(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);
+ tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(localPoolName), childPool);
+ tx.submit().get();
+ requestIdsConcurrently(true);
+ coordinatorEventsWaiter.awaitEventsConsumption();
+
+ validateIdPools(ExpectedAllocateIdFromReleasedId.idPoolParent(),
+ ExpectedAllocateIdFromReleasedId.idPoolChild());
}
- private AllocateIdInput buildAllocateId(String poolName, String idKey) {
- AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(poolName)
- .setIdKey(idKey).build();
- return getIdInput;
+ @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 = 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;
+ } else {
+ 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());
+ try {
+ if (result.get().isSuccessful()) {
+ Long idValue = result.get().getResult().getIdValue();
+ idSet.add(idValue);
+ if (idValue > ID_LOW + BLOCK_SIZE) {
+ exceptionInExecutorAtomic.set(new AssertionFailedError("idValue <= ID_LOW + BLOCK_SIZE"));
+ }
+ } else {
+ RpcError error = result.get().getErrors().iterator().next();
+ if (!error.getCause().getMessage().contains("Ids exhausted for pool : " + ID_POOL_NAME)) {
+ exceptionInExecutorAtomic.set(error.getCause());
+ }
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ exceptionInExecutorAtomic.set(e);
+ } finally {
+ latch.countDown();
+ }
+ });
+ }
+ if (!latch.await(13, SECONDS)) {
+ fail("latch.await(13, SECONDS) timed out :(");
+ }
+ Throwable exceptionInExecutor = exceptionInExecutorAtomic.get();
+ if (exceptionInExecutor != null) {
+ throw exceptionInExecutor;
+ }
+ if (isSameKey) {
+ assertEquals(1, idSet.size());
+ } else {
+ assertEquals(numberOfTasks, idSet.size());
+ }
}
- private InstanceIdentifier<IdPool> buildInstanceIdentifier(String poolName) {
+ 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 AvailableIdsHolder createAvailableIdsHolder(long low, long high, long cursor) {
- AvailableIdsHolder availableIdsHolder = new AvailableIdsHolderBuilder()
- .setStart(low).setEnd(high).setCursor(cursor).build();
- return availableIdsHolder;
+ private ReleasedIdsHolder createReleaseIdHolder(List<Long> delayedIds) {
+ List<DelayedIdEntries> delayedIdEntries = new ArrayList<>();
+ for (Long id : delayedIds) {
+ delayedIdEntries.add(new DelayedIdEntriesBuilder().setId(id).setReadyTimeSec(0L).build());
+ }
+ return new ReleasedIdsHolderBuilder().setDelayedIdEntries(delayedIdEntries)
+ .setAvailableIdCount((long) delayedIds.size()).build();
}
- private ReleasedIdsHolder createReleasedIdsHolder(long availableIdCount, List<DelayedIdEntries> delayedIdEntries, long delayTime) {
- ReleasedIdsHolder releasedIdsHolder = new ReleasedIdsHolderBuilder()
- .setAvailableIdCount(availableIdCount)
- .setDelayedIdEntries(delayedIdEntries)
- .setDelayedTimeSec(delayTime).build();
- return releasedIdsHolder;
+ private AvailableIdsHolder createAvailableIdHolder(long start, long end, long cursor) {
+ return new AvailableIdsHolderBuilder().setStart(start).setEnd(end).setCursor(cursor).build();
}
- private DeleteIdPoolInput createDeleteIdPoolInput(String poolName) {
- return new DeleteIdPoolInputBuilder().setPoolName(poolName).build();
+ private void validateIdPools(IdPool expectedIdPoolParent, IdPool expectedIdPoolChild)
+ throws ReadFailedException, ComparisonFailure {
+ IdPool actualIdPoolParent = getUpdatedActualParentPool();
+ IdPool actualIdPoolChild = getUpdatedActualChildPool();
+
+ assertNotNull(actualIdPoolParent);
+ assertNotNull(actualIdPoolChild);
+ AssertDataObjects.assertEqualBeans(expectedIdPoolParent, actualIdPoolParent);
+ AssertDataObjects.assertEqualBeans(expectedIdPoolChild, actualIdPoolChild);
+
}
- private List<DelayedIdEntries> buildDelayedIdEntries(long[] idValues) {
- List<DelayedIdEntries> delayedIdEntriesList = new ArrayList<DelayedIdEntries>();
- for (long idValue : idValues) {
- DelayedIdEntries delayedIdEntries = new DelayedIdEntriesBuilder().setId(idValue).setReadyTimeSec(0L).build();
- delayedIdEntriesList.add(delayedIdEntries);
+ private IdPool getUpdatedActualChildPool() throws ReadFailedException {
+ String localPoolName = idUtils.getLocalPoolName(ID_POOL_NAME);
+ IdPool idPoolChildFromDS = singleTxdataBroker.syncRead(LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(localPoolName)).build());
+ List<DelayedIdEntries> actualDelayedIdEntries = idPoolChildFromDS.getReleasedIdsHolder().getDelayedIdEntries();
+ IdPool actualIdPoolChild = idPoolChildFromDS;
+ if (actualDelayedIdEntries != null) {
+ List<DelayedIdEntries> updatedDelayedIdEntries = actualDelayedIdEntries.stream()
+ .map(delayedIdEntry -> new DelayedIdEntriesBuilder().setId(delayedIdEntry.getId())
+ .setReadyTimeSec(0L).build())
+ .collect(Collectors.toList());
+ ReleasedIdsHolder releasedId = new ReleasedIdsHolderBuilder(idPoolChildFromDS.getReleasedIdsHolder())
+ .setDelayedIdEntries(updatedDelayedIdEntries).build();
+ actualIdPoolChild = new IdPoolBuilder(idPoolChildFromDS).setReleasedIdsHolder(releasedId).build();
}
- return delayedIdEntriesList;
+ return actualIdPoolChild;
}
- private List<ChildPools> buildChildPool(String childPoolName) {
- ChildPools childPools = new ChildPoolsBuilder().setChildPoolName(childPoolName).build();
- List<ChildPools> childPoolsList = new ArrayList<ChildPools>();
- childPoolsList.add(childPools);
- return childPoolsList;
+ 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 = nullToEmpty(idPoolParentFromDS.getChildPools());
+ List<ChildPools> updatedChildPool = childPool.stream()
+ .map(child -> new ChildPoolsBuilder(child).setLastAccessTime(0L).build()).collect(Collectors.toList());
+ List<IdEntries> idEntries = idPoolParentFromDS.getIdEntries();
+ IdPoolBuilder idPoolBuilder = new IdPoolBuilder(idPoolParentFromDS);
+ if (idEntries != null) {
+ List<IdEntries> sortedIdEntries = idEntries.stream().sorted(comparing(IdEntries::getIdKey))
+ .collect(Collectors.toList());
+ idPoolBuilder.setIdEntries(sortedIdEntries);
+ }
+ return idPoolBuilder.setChildPools(updatedChildPool).build();
}
-}
\ No newline at end of file
+}