4c0b1c0385455ff4deed2a17716c81561810807d
[genius.git] / idmanager / idmanager-impl / src / test / java / org / opendaylight / genius / idmanager / test / IdManagerTest.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.genius.idmanager.test;
9
10 import static java.util.Comparator.comparing;
11 import static java.util.concurrent.TimeUnit.SECONDS;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertFalse;
14 import static org.junit.Assert.assertNotNull;
15 import static org.junit.Assert.assertTrue;
16 import static org.junit.Assert.fail;
17
18 import com.google.common.collect.Sets;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.Optional;
24 import java.util.Set;
25 import java.util.concurrent.CountDownLatch;
26 import java.util.concurrent.ExecutionException;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.Future;
29 import java.util.concurrent.atomic.AtomicReference;
30 import java.util.stream.Collectors;
31 import javax.inject.Inject;
32 import junit.framework.AssertionFailedError;
33 import org.junit.Before;
34 import org.junit.ComparisonFailure;
35 import org.junit.Rule;
36 import org.junit.Test;
37 import org.junit.rules.MethodRule;
38 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
39 import org.opendaylight.genius.datastoreutils.testutils.AsyncEventsWaiter;
40 import org.opendaylight.genius.datastoreutils.testutils.JobCoordinatorEventsWaiter;
41 import org.opendaylight.genius.datastoreutils.testutils.JobCoordinatorTestModule;
42 import org.opendaylight.genius.datastoreutils.testutils.TestableDataTreeChangeListenerModule;
43 import org.opendaylight.genius.idmanager.IdUtils;
44 import org.opendaylight.infrautils.inject.guice.testutils.GuiceRule;
45 import org.opendaylight.infrautils.testutils.LogCaptureRule;
46 import org.opendaylight.infrautils.testutils.LogRule;
47 import org.opendaylight.infrautils.utils.concurrent.Executors;
48 import org.opendaylight.mdsal.binding.api.DataBroker;
49 import org.opendaylight.mdsal.binding.api.WriteTransaction;
50 import org.opendaylight.mdsal.binding.testutils.AssertDataObjects;
51 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
52 import org.opendaylight.mdsal.common.api.ReadFailedException;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInputBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdPools;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdOutput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPool;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolderBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPools;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPoolsBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntries;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolderBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntries;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntriesBuilder;
77 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
78 import org.opendaylight.yangtools.yang.common.RpcError;
79 import org.opendaylight.yangtools.yang.common.RpcResult;
80 import org.slf4j.Logger;
81 import org.slf4j.LoggerFactory;
82
83
84 public class IdManagerTest {
85
86     private static final Logger LOG = LoggerFactory.getLogger(IdManagerTest.class);
87
88     private static final String TEST_KEY1 = "test-key1";
89     private static final String TEST_KEY2 = "test-key2";
90     private static final String ID_POOL_NAME = "test-pool";
91     private static final int BLOCK_SIZE = 10;
92     private static final long ID_LOW = 0L;
93     private static final long ID_HIGH = 100L;
94
95     // public static @ClassRule RunUntilFailureClassRule classRepeater = new RunUntilFailureClassRule();
96     // public @Rule RunUntilFailureRule repeater = new RunUntilFailureRule(classRepeater);
97
98     public @Rule LogRule logRule = new LogRule();
99     public @Rule LogCaptureRule logCaptureRule = new LogCaptureRule();
100
101     public @Rule MethodRule guice = new GuiceRule(IdManagerTestModule.class,
102             TestableDataTreeChangeListenerModule.class, JobCoordinatorTestModule.class);
103
104     private @Inject IdManagerService idManagerService;
105     private @Inject DataBroker dataBroker;
106     private @Inject AsyncEventsWaiter asyncEventsWaiter;
107     private @Inject JobCoordinatorEventsWaiter coordinatorEventsWaiter;
108     private @Inject IdUtils idUtils;
109
110     private SingleTransactionDataBroker singleTxdataBroker;
111
112     @Before
113     public void before() {
114         singleTxdataBroker = new SingleTransactionDataBroker(dataBroker);
115     }
116
117     @Test
118     public void testCreateIdPool() throws Exception {
119         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
120                 .setPoolName(ID_POOL_NAME).build();
121         assertTrue(idManagerService.createIdPool(createIdPoolInput).get().isSuccessful());
122         coordinatorEventsWaiter.awaitEventsConsumption();
123         validateIdPools(ExpectedCreateIdPoolObjects.idPoolCreateParent(),
124                 ExpectedCreateIdPoolObjects.idPoolCreateChild());
125     }
126
127     @Test
128     public void testAllocateId() throws Exception {
129         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
130                 .setPoolName(ID_POOL_NAME).build();
131         AllocateIdInput allocateIdInput = new AllocateIdInputBuilder().setIdKey(TEST_KEY1).setPoolName(ID_POOL_NAME)
132                 .build();
133         idManagerService.createIdPool(createIdPoolInput);
134         assertEquals(idManagerService.allocateId(allocateIdInput).get().getResult().getIdValue().longValue(), 0L);
135         coordinatorEventsWaiter.awaitEventsConsumption();
136
137         validateIdPools(ExpectedAllocateIdObjects.idPoolParent(), ExpectedAllocateIdObjects.idPoolChild());
138     }
139
140     @Test
141     public void testReleaseId() throws Exception {
142         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
143                 .setPoolName(ID_POOL_NAME).build();
144         AllocateIdInput allocateIdInput = new AllocateIdInputBuilder().setIdKey(TEST_KEY1).setPoolName(ID_POOL_NAME)
145                 .build();
146         ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setIdKey(TEST_KEY1).setPoolName(ID_POOL_NAME)
147                 .build();
148         idManagerService.createIdPool(createIdPoolInput);
149         Future<RpcResult<AllocateIdOutput>> allocateIdResult = idManagerService.allocateId(allocateIdInput);
150         assertTrue(allocateIdResult.get().isSuccessful());
151         Future<RpcResult<ReleaseIdOutput>> result = idManagerService.releaseId(releaseIdInput);
152         assertTrue(result.get().isSuccessful());
153         assertEquals(allocateIdResult.get().getResult().getIdValue(), result.get().getResult().getIdValues().get(0));
154         coordinatorEventsWaiter.awaitEventsConsumption();
155
156         validateIdPools(ExpectedReleaseIdObjects.idPoolParent(), ExpectedReleaseIdObjects.idPoolChild());
157     }
158
159     @Test
160     public void testAllocateIdBlockFromReleasedIds() throws Exception {
161         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
162                 .setPoolName(ID_POOL_NAME).build();
163         AllocateIdInput allocateIdInput = new AllocateIdInputBuilder().setIdKey(TEST_KEY2).setPoolName(ID_POOL_NAME)
164                 .build();
165         idManagerService.createIdPool(createIdPoolInput);
166         idManagerService.allocateId(allocateIdInput);
167         coordinatorEventsWaiter.awaitEventsConsumption();
168         asyncEventsWaiter.awaitEventsConsumption();
169
170         String localPoolName = idUtils.getLocalPoolName(ID_POOL_NAME);
171         IdPool parentIdPool = new IdPoolBuilder().setPoolName(ID_POOL_NAME).withKey(new IdPoolKey(ID_POOL_NAME))
172                 .setAvailableIdsHolder(createAvailableIdHolder(ID_LOW, ID_HIGH, ID_HIGH + 1))
173                 .setReleasedIdsHolder(createReleaseIdHolder(Arrays.asList(1L, 2L, 3L))).build();
174         IdPool childPool = new IdPoolBuilder().setPoolName(localPoolName).withKey(new IdPoolKey(localPoolName))
175                 .setAvailableIdsHolder(createAvailableIdHolder(0L, 9L, 10L)).build();
176         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
177         tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(ID_POOL_NAME), parentIdPool);
178         tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(localPoolName), childPool);
179         tx.commit().get();
180
181         AllocateIdInput allocateIdInput2 = new AllocateIdInputBuilder().setIdKey(TEST_KEY1).setPoolName(ID_POOL_NAME)
182                 .build();
183         assertEquals(idManagerService.allocateId(allocateIdInput2).get().getResult().getIdValue().longValue(), 1L);
184
185         coordinatorEventsWaiter.awaitEventsConsumption();
186         validateIdPools(ExpectedAllocateIdFromReleasedId.idPoolParent(),
187                 ExpectedAllocateIdFromReleasedId.idPoolChild());
188     }
189
190     @Test
191     public void testDeletePool() throws Exception {
192         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
193                 .setPoolName(ID_POOL_NAME).build();
194         idManagerService.createIdPool(createIdPoolInput);
195         DeleteIdPoolInput deleteIdPoolInput = new DeleteIdPoolInputBuilder().setPoolName(ID_POOL_NAME).build();
196         assertTrue(idManagerService.deleteIdPool(deleteIdPoolInput).get().isSuccessful());
197         coordinatorEventsWaiter.awaitEventsConsumption();
198         Optional<IdPool> actualIdPoolParent = singleTxdataBroker.syncReadOptional(LogicalDatastoreType.CONFIGURATION,
199                 InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(ID_POOL_NAME)).build());
200         Optional<IdPool> actualIdPoolChild = singleTxdataBroker.syncReadOptional(LogicalDatastoreType.CONFIGURATION,
201                 InstanceIdentifier.builder(IdPools.class)
202                         .child(IdPool.class, new IdPoolKey(idUtils.getLocalPoolName(ID_POOL_NAME))).build());
203         assertFalse(actualIdPoolParent.isPresent());
204         assertFalse(actualIdPoolChild.isPresent());
205     }
206
207     @Test
208     @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
209     public void testMultithreadedIdAllocationFromAvailableIds() throws Throwable {
210         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
211                 .setPoolName(ID_POOL_NAME).build();
212         idManagerService.createIdPool(createIdPoolInput);
213         requestIdsConcurrently(false);
214         coordinatorEventsWaiter.awaitEventsConsumption();
215         IdPool actualIdPoolChild = getUpdatedActualChildPool();
216         IdPool actualIdPoolParent = getUpdatedActualParentPool();
217         // Cannot compare the idEntries since we cannot guarantee which idKey gets what value.
218         // However the allocated id values uniqueness is verified in requestIdsConcurrently method.
219         AssertDataObjects.assertEqualBeans(
220                 ExpectedAllocateIdMultipleRequestsFromAvailableIds.idPoolParent().getAvailableIdsHolder(),
221                 actualIdPoolParent.getAvailableIdsHolder());
222         AssertDataObjects.assertEqualBeans(ExpectedAllocateIdMultipleRequestsFromAvailableIds.idPoolChild(),
223                 actualIdPoolChild);
224     }
225
226     @Test
227     @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
228     public void testMultithreadedIdAllocationFromReleaseIds() throws Throwable {
229         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
230                 .setPoolName(ID_POOL_NAME).build();
231         AllocateIdInput allocateIdInput = new AllocateIdInputBuilder().setIdKey(TEST_KEY1).setPoolName(ID_POOL_NAME)
232                 .build();
233         idManagerService.createIdPool(createIdPoolInput);
234         idManagerService.allocateId(allocateIdInput);
235         // Should wait for all job to complete.
236         coordinatorEventsWaiter.awaitEventsConsumption();
237
238         String localPoolName = idUtils.getLocalPoolName(ID_POOL_NAME);
239         IdPool parentIdPool = new IdPoolBuilder().setPoolName(ID_POOL_NAME).withKey(new IdPoolKey(ID_POOL_NAME))
240                 .setReleasedIdsHolder(createReleaseIdHolder(Collections.emptyList())).build();
241         IdPool childPool = new IdPoolBuilder().setPoolName(localPoolName).withKey(new IdPoolKey(localPoolName))
242                 .setReleasedIdsHolder(createReleaseIdHolder(Arrays.asList(1L, 2L, 3L)))
243                 .setAvailableIdsHolder(createAvailableIdHolder(0L, 9L, 10L)).build();
244         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
245         tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(ID_POOL_NAME), parentIdPool);
246         tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(localPoolName), childPool);
247         tx.commit().get();
248         // Wait for the changes to be available on the caches.
249         asyncEventsWaiter.awaitEventsConsumption();
250         requestIdsConcurrently(false);
251         coordinatorEventsWaiter.awaitEventsConsumption();
252         asyncEventsWaiter.awaitEventsConsumption();
253
254         IdPool actualIdPoolChild = getUpdatedActualChildPool();
255         IdPool actualIdPoolParent = getUpdatedActualParentPool();
256         // Cannot compare the idEntries since we cannot guarantee which idKey gets what value.
257         // However the allocated id values uniqueness is verified in requestIdsConcurrently method.
258         AssertDataObjects.assertEqualBeans(
259                 ExpectedAllocateIdMultipleRequestsFromReleaseIds.idPoolParent().getReleasedIdsHolder(),
260                 actualIdPoolParent.getReleasedIdsHolder());
261         AssertDataObjects.assertEqualBeans(ExpectedAllocateIdMultipleRequestsFromReleaseIds.idPoolChild(),
262                 actualIdPoolChild);
263     }
264
265     @Test
266     @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
267     public void testMultithreadedIdAllocationForSameKeyFromAvailableIds() throws Throwable {
268         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
269                 .setPoolName(ID_POOL_NAME).build();
270         idManagerService.createIdPool(createIdPoolInput);
271         requestIdsConcurrently(true);
272         coordinatorEventsWaiter.awaitEventsConsumption();
273
274         validateIdPools(ExpectedAllocateIdObjects.idPoolParent(), ExpectedAllocateIdObjects.idPoolChild());
275     }
276
277     @Test
278     @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
279     public void testMultithreadedIdAllocationForSameKeyFromReleasedIds() throws Throwable {
280         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
281                 .setPoolName(ID_POOL_NAME).build();
282         AllocateIdInput allocateIdInput = new AllocateIdInputBuilder().setIdKey(TEST_KEY2).setPoolName(ID_POOL_NAME)
283                 .build();
284         idManagerService.createIdPool(createIdPoolInput);
285         idManagerService.allocateId(allocateIdInput);
286         coordinatorEventsWaiter.awaitEventsConsumption();
287         asyncEventsWaiter.awaitEventsConsumption();
288
289         String localPoolName = idUtils.getLocalPoolName(ID_POOL_NAME);
290         IdPool parentIdPool = new IdPoolBuilder().setPoolName(ID_POOL_NAME).withKey(new IdPoolKey(ID_POOL_NAME))
291                 .setAvailableIdsHolder(createAvailableIdHolder(ID_LOW, ID_HIGH, ID_HIGH + 1))
292                 .setReleasedIdsHolder(createReleaseIdHolder(Collections.emptyList())).build();
293         IdPool childPool = new IdPoolBuilder().setPoolName(localPoolName).withKey(new IdPoolKey(localPoolName))
294                 .setReleasedIdsHolder(createReleaseIdHolder(Arrays.asList(1L, 2L, 3L)))
295                 .setAvailableIdsHolder(createAvailableIdHolder(0L, 9L, 10L)).build();
296         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
297         tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(ID_POOL_NAME), parentIdPool);
298         tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(localPoolName), childPool);
299         tx.commit().get();
300         requestIdsConcurrently(true);
301         coordinatorEventsWaiter.awaitEventsConsumption();
302
303         validateIdPools(ExpectedAllocateIdFromReleasedId.idPoolParent(),
304                 ExpectedAllocateIdFromReleasedId.idPoolChild());
305     }
306
307     @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
308     private void requestIdsConcurrently(boolean isSameKey) throws Throwable {
309         int numberOfTasks = 3;
310         CountDownLatch latch = new CountDownLatch(numberOfTasks);
311         Set<Long> idSet = Sets.newConcurrentHashSet();
312         ExecutorService executor = Executors.newCachedThreadPool("requestIdsConcurrently()", LOG);
313         AtomicReference<Throwable> exceptionInExecutorAtomic = new AtomicReference<>();
314         for (int i = 0; i < numberOfTasks; i++) {
315             final String idKey;
316             if (isSameKey) {
317                 idKey = TEST_KEY1;
318             } else {
319                 idKey = TEST_KEY1 + i;
320             }
321             executor.execute(() -> {
322                 // Any exception thrown inside this background thread will not cause the test to fail
323                 // so you cannot use assert* here but must set the exceptionInExecutor which is checked after
324                 Future<RpcResult<AllocateIdOutput>> result;
325                 result = idManagerService.allocateId(
326                         new AllocateIdInputBuilder().setPoolName(ID_POOL_NAME).setIdKey(idKey).build());
327                 try {
328                     if (result.get().isSuccessful()) {
329                         Long idValue = result.get().getResult().getIdValue().toJava();
330                         idSet.add(idValue);
331                         if (idValue > ID_LOW + BLOCK_SIZE) {
332                             exceptionInExecutorAtomic.set(new AssertionFailedError("idValue <= ID_LOW + BLOCK_SIZE"));
333                         }
334                     } else {
335                         RpcError error = result.get().getErrors().iterator().next();
336                         if (!error.getCause().getMessage().contains("Ids exhausted for pool : " + ID_POOL_NAME)) {
337                             exceptionInExecutorAtomic.set(error.getCause());
338                         }
339                     }
340                 } catch (InterruptedException | ExecutionException e) {
341                     exceptionInExecutorAtomic.set(e);
342                 } finally {
343                     latch.countDown();
344                 }
345             });
346         }
347         if (!latch.await(13, SECONDS)) {
348             fail("latch.await(13, SECONDS) timed out :(");
349         }
350         Throwable exceptionInExecutor = exceptionInExecutorAtomic.get();
351         if (exceptionInExecutor != null) {
352             throw exceptionInExecutor;
353         }
354         if (isSameKey) {
355             assertEquals(1, idSet.size());
356         } else {
357             assertEquals(numberOfTasks, idSet.size());
358         }
359     }
360
361     private InstanceIdentifier<IdPool> getIdPoolIdentifier(String poolName) {
362         InstanceIdentifier.InstanceIdentifierBuilder<IdPool> idBuilder =
363                 InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(poolName));
364         return idBuilder.build();
365     }
366
367     private ReleasedIdsHolder createReleaseIdHolder(List<Long> delayedIds) {
368         List<DelayedIdEntries> delayedIdEntries = new ArrayList<>();
369         for (Long id : delayedIds) {
370             delayedIdEntries.add(new DelayedIdEntriesBuilder().setId(id).setReadyTimeSec(0L).build());
371         }
372         return new ReleasedIdsHolderBuilder().setDelayedIdEntries(delayedIdEntries)
373                 .setAvailableIdCount((long) delayedIds.size()).build();
374     }
375
376     private AvailableIdsHolder createAvailableIdHolder(long start, long end, long cursor) {
377         return new AvailableIdsHolderBuilder().setStart(start).setEnd(end).setCursor(cursor).build();
378     }
379
380     private void validateIdPools(IdPool expectedIdPoolParent, IdPool expectedIdPoolChild)
381             throws ReadFailedException, ComparisonFailure {
382         IdPool actualIdPoolParent = getUpdatedActualParentPool();
383         IdPool actualIdPoolChild = getUpdatedActualChildPool();
384
385         assertNotNull(actualIdPoolParent);
386         assertNotNull(actualIdPoolChild);
387         AssertDataObjects.assertEqualBeans(expectedIdPoolParent, actualIdPoolParent);
388         AssertDataObjects.assertEqualBeans(expectedIdPoolChild, actualIdPoolChild);
389
390     }
391
392     private IdPool getUpdatedActualChildPool() throws ReadFailedException {
393         String localPoolName = idUtils.getLocalPoolName(ID_POOL_NAME);
394         IdPool idPoolChildFromDS = singleTxdataBroker.syncRead(LogicalDatastoreType.CONFIGURATION,
395                 InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(localPoolName)).build());
396         List<DelayedIdEntries> actualDelayedIdEntries = idPoolChildFromDS.getReleasedIdsHolder().getDelayedIdEntries();
397         IdPool actualIdPoolChild = idPoolChildFromDS;
398         if (actualDelayedIdEntries != null) {
399             List<DelayedIdEntries> updatedDelayedIdEntries = actualDelayedIdEntries.stream()
400                     .map(delayedIdEntry -> new DelayedIdEntriesBuilder().setId(delayedIdEntry.getId())
401                             .setReadyTimeSec(0L).build())
402                     .collect(Collectors.toList());
403             ReleasedIdsHolder releasedId = new ReleasedIdsHolderBuilder(idPoolChildFromDS.getReleasedIdsHolder())
404                     .setDelayedIdEntries(updatedDelayedIdEntries).build();
405             actualIdPoolChild = new IdPoolBuilder(idPoolChildFromDS).setReleasedIdsHolder(releasedId).build();
406         }
407         return actualIdPoolChild;
408     }
409
410     private IdPool getUpdatedActualParentPool() throws ReadFailedException {
411         IdPool idPoolParentFromDS = singleTxdataBroker.syncRead(LogicalDatastoreType.CONFIGURATION,
412                 InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(ID_POOL_NAME)).build());
413         List<ChildPools> childPool = idPoolParentFromDS.nonnullChildPools();
414         List<ChildPools> updatedChildPool = childPool.stream()
415                 .map(child -> new ChildPoolsBuilder(child).setLastAccessTime(0L).build()).collect(Collectors.toList());
416         List<IdEntries> idEntries = idPoolParentFromDS.getIdEntries();
417         IdPoolBuilder idPoolBuilder = new IdPoolBuilder(idPoolParentFromDS);
418         if (idEntries != null) {
419             List<IdEntries> sortedIdEntries = idEntries.stream().sorted(comparing(IdEntries::getIdKey))
420                     .collect(Collectors.toList());
421             idPoolBuilder.setIdEntries(sortedIdEntries);
422         }
423         return idPoolBuilder.setChildPools(updatedChildPool).build();
424     }
425 }