Handle nullable lists
[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 import static org.opendaylight.genius.idmanager.IdUtils.nullToEmpty;
18
19 import com.google.common.base.Optional;
20 import com.google.common.collect.Sets;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.Set;
26 import java.util.concurrent.CountDownLatch;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.Future;
30 import java.util.concurrent.atomic.AtomicReference;
31 import java.util.stream.Collectors;
32 import javax.inject.Inject;
33 import junit.framework.AssertionFailedError;
34 import org.junit.Before;
35 import org.junit.ComparisonFailure;
36 import org.junit.Rule;
37 import org.junit.Test;
38 import org.junit.rules.MethodRule;
39 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
40 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
41 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
42 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
43 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
44 import org.opendaylight.genius.datastoreutils.testutils.AsyncEventsWaiter;
45 import org.opendaylight.genius.datastoreutils.testutils.JobCoordinatorEventsWaiter;
46 import org.opendaylight.genius.datastoreutils.testutils.JobCoordinatorTestModule;
47 import org.opendaylight.genius.datastoreutils.testutils.TestableDataTreeChangeListenerModule;
48 import org.opendaylight.genius.idmanager.IdUtils;
49 import org.opendaylight.infrautils.inject.guice.testutils.GuiceRule;
50 import org.opendaylight.infrautils.testutils.LogCaptureRule;
51 import org.opendaylight.infrautils.testutils.LogRule;
52 import org.opendaylight.infrautils.utils.concurrent.Executors;
53 import org.opendaylight.mdsal.binding.testutils.AssertDataObjects;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInputBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdPools;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
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         idManagerService.allocateId(allocateIdInput);
150         assertTrue(idManagerService.releaseId(releaseIdInput).get().isSuccessful());
151         coordinatorEventsWaiter.awaitEventsConsumption();
152
153         validateIdPools(ExpectedReleaseIdObjects.idPoolParent(), ExpectedReleaseIdObjects.idPoolChild());
154     }
155
156     @Test
157     public void testAllocateIdBlockFromReleasedIds() throws Exception {
158         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
159                 .setPoolName(ID_POOL_NAME).build();
160         AllocateIdInput allocateIdInput = new AllocateIdInputBuilder().setIdKey(TEST_KEY2).setPoolName(ID_POOL_NAME)
161                 .build();
162         idManagerService.createIdPool(createIdPoolInput);
163         idManagerService.allocateId(allocateIdInput);
164         coordinatorEventsWaiter.awaitEventsConsumption();
165         asyncEventsWaiter.awaitEventsConsumption();
166
167         String localPoolName = idUtils.getLocalPoolName(ID_POOL_NAME);
168         IdPool parentIdPool = new IdPoolBuilder().setPoolName(ID_POOL_NAME).withKey(new IdPoolKey(ID_POOL_NAME))
169                 .setAvailableIdsHolder(createAvailableIdHolder(ID_LOW, ID_HIGH, ID_HIGH + 1))
170                 .setReleasedIdsHolder(createReleaseIdHolder(Arrays.asList(1L, 2L, 3L))).build();
171         IdPool childPool = new IdPoolBuilder().setPoolName(localPoolName).withKey(new IdPoolKey(localPoolName))
172                 .setAvailableIdsHolder(createAvailableIdHolder(0L, 9L, 10L)).build();
173         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
174         tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(ID_POOL_NAME), parentIdPool);
175         tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(localPoolName), childPool);
176         tx.submit().get();
177
178         AllocateIdInput allocateIdInput2 = new AllocateIdInputBuilder().setIdKey(TEST_KEY1).setPoolName(ID_POOL_NAME)
179                 .build();
180         assertEquals(idManagerService.allocateId(allocateIdInput2).get().getResult().getIdValue().longValue(), 1L);
181
182         coordinatorEventsWaiter.awaitEventsConsumption();
183         validateIdPools(ExpectedAllocateIdFromReleasedId.idPoolParent(),
184                 ExpectedAllocateIdFromReleasedId.idPoolChild());
185     }
186
187     @Test
188     public void testDeletePool() throws Exception {
189         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
190                 .setPoolName(ID_POOL_NAME).build();
191         idManagerService.createIdPool(createIdPoolInput);
192         DeleteIdPoolInput deleteIdPoolInput = new DeleteIdPoolInputBuilder().setPoolName(ID_POOL_NAME).build();
193         assertTrue(idManagerService.deleteIdPool(deleteIdPoolInput).get().isSuccessful());
194         coordinatorEventsWaiter.awaitEventsConsumption();
195         Optional<IdPool> actualIdPoolParent = singleTxdataBroker.syncReadOptional(LogicalDatastoreType.CONFIGURATION,
196                 InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(ID_POOL_NAME)).build());
197         Optional<IdPool> actualIdPoolChild = singleTxdataBroker.syncReadOptional(LogicalDatastoreType.CONFIGURATION,
198                 InstanceIdentifier.builder(IdPools.class)
199                         .child(IdPool.class, new IdPoolKey(idUtils.getLocalPoolName(ID_POOL_NAME))).build());
200         assertFalse(actualIdPoolParent.isPresent());
201         assertFalse(actualIdPoolChild.isPresent());
202     }
203
204     @Test
205     @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
206     public void testMultithreadedIdAllocationFromAvailableIds() throws Throwable {
207         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
208                 .setPoolName(ID_POOL_NAME).build();
209         idManagerService.createIdPool(createIdPoolInput);
210         requestIdsConcurrently(false);
211         coordinatorEventsWaiter.awaitEventsConsumption();
212         IdPool actualIdPoolChild = getUpdatedActualChildPool();
213         IdPool actualIdPoolParent = getUpdatedActualParentPool();
214         // Cannot compare the idEntries since we cannot guarantee which idKey gets what value.
215         // However the allocated id values uniqueness is verified in requestIdsConcurrently method.
216         AssertDataObjects.assertEqualBeans(
217                 ExpectedAllocateIdMultipleRequestsFromAvailableIds.idPoolParent().getAvailableIdsHolder(),
218                 actualIdPoolParent.getAvailableIdsHolder());
219         AssertDataObjects.assertEqualBeans(ExpectedAllocateIdMultipleRequestsFromAvailableIds.idPoolChild(),
220                 actualIdPoolChild);
221     }
222
223     @Test
224     @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
225     public void testMultithreadedIdAllocationFromReleaseIds() throws Throwable {
226         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
227                 .setPoolName(ID_POOL_NAME).build();
228         AllocateIdInput allocateIdInput = new AllocateIdInputBuilder().setIdKey(TEST_KEY1).setPoolName(ID_POOL_NAME)
229                 .build();
230         idManagerService.createIdPool(createIdPoolInput);
231         idManagerService.allocateId(allocateIdInput);
232         // Should wait for all job to complete.
233         coordinatorEventsWaiter.awaitEventsConsumption();
234
235         String localPoolName = idUtils.getLocalPoolName(ID_POOL_NAME);
236         IdPool parentIdPool = new IdPoolBuilder().setPoolName(ID_POOL_NAME).withKey(new IdPoolKey(ID_POOL_NAME))
237                 .setReleasedIdsHolder(createReleaseIdHolder(Collections.emptyList())).build();
238         IdPool childPool = new IdPoolBuilder().setPoolName(localPoolName).withKey(new IdPoolKey(localPoolName))
239                 .setReleasedIdsHolder(createReleaseIdHolder(Arrays.asList(1L, 2L, 3L)))
240                 .setAvailableIdsHolder(createAvailableIdHolder(0L, 9L, 10L)).build();
241         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
242         tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(ID_POOL_NAME), parentIdPool);
243         tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(localPoolName), childPool);
244         tx.submit().get();
245         // Wait for the changes to be available on the caches.
246         asyncEventsWaiter.awaitEventsConsumption();
247         requestIdsConcurrently(false);
248         coordinatorEventsWaiter.awaitEventsConsumption();
249         asyncEventsWaiter.awaitEventsConsumption();
250
251         IdPool actualIdPoolChild = getUpdatedActualChildPool();
252         IdPool actualIdPoolParent = getUpdatedActualParentPool();
253         // Cannot compare the idEntries since we cannot guarantee which idKey gets what value.
254         // However the allocated id values uniqueness is verified in requestIdsConcurrently method.
255         AssertDataObjects.assertEqualBeans(
256                 ExpectedAllocateIdMultipleRequestsFromReleaseIds.idPoolParent().getReleasedIdsHolder(),
257                 actualIdPoolParent.getReleasedIdsHolder());
258         AssertDataObjects.assertEqualBeans(ExpectedAllocateIdMultipleRequestsFromReleaseIds.idPoolChild(),
259                 actualIdPoolChild);
260     }
261
262     @Test
263     @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
264     public void testMultithreadedIdAllocationForSameKeyFromAvailableIds() throws Throwable {
265         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
266                 .setPoolName(ID_POOL_NAME).build();
267         idManagerService.createIdPool(createIdPoolInput);
268         requestIdsConcurrently(true);
269         coordinatorEventsWaiter.awaitEventsConsumption();
270
271         validateIdPools(ExpectedAllocateIdObjects.idPoolParent(), ExpectedAllocateIdObjects.idPoolChild());
272     }
273
274     @Test
275     @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
276     public void testMultithreadedIdAllocationForSameKeyFromReleasedIds() throws Throwable {
277         CreateIdPoolInput createIdPoolInput = new CreateIdPoolInputBuilder().setHigh(ID_HIGH).setLow(ID_LOW)
278                 .setPoolName(ID_POOL_NAME).build();
279         AllocateIdInput allocateIdInput = new AllocateIdInputBuilder().setIdKey(TEST_KEY2).setPoolName(ID_POOL_NAME)
280                 .build();
281         idManagerService.createIdPool(createIdPoolInput);
282         idManagerService.allocateId(allocateIdInput);
283         coordinatorEventsWaiter.awaitEventsConsumption();
284         asyncEventsWaiter.awaitEventsConsumption();
285
286         String localPoolName = idUtils.getLocalPoolName(ID_POOL_NAME);
287         IdPool parentIdPool = new IdPoolBuilder().setPoolName(ID_POOL_NAME).withKey(new IdPoolKey(ID_POOL_NAME))
288                 .setAvailableIdsHolder(createAvailableIdHolder(ID_LOW, ID_HIGH, ID_HIGH + 1))
289                 .setReleasedIdsHolder(createReleaseIdHolder(Collections.emptyList())).build();
290         IdPool childPool = new IdPoolBuilder().setPoolName(localPoolName).withKey(new IdPoolKey(localPoolName))
291                 .setReleasedIdsHolder(createReleaseIdHolder(Arrays.asList(1L, 2L, 3L)))
292                 .setAvailableIdsHolder(createAvailableIdHolder(0L, 9L, 10L)).build();
293         WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
294         tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(ID_POOL_NAME), parentIdPool);
295         tx.merge(LogicalDatastoreType.CONFIGURATION, getIdPoolIdentifier(localPoolName), childPool);
296         tx.submit().get();
297         requestIdsConcurrently(true);
298         coordinatorEventsWaiter.awaitEventsConsumption();
299
300         validateIdPools(ExpectedAllocateIdFromReleasedId.idPoolParent(),
301                 ExpectedAllocateIdFromReleasedId.idPoolChild());
302     }
303
304     @SuppressWarnings("checkstyle:IllegalThrows") // OK as exceptionInExecutor can't be Exception & AssertionFailedError
305     private void requestIdsConcurrently(boolean isSameKey) throws Throwable {
306         int numberOfTasks = 3;
307         CountDownLatch latch = new CountDownLatch(numberOfTasks);
308         Set<Long> idSet = Sets.newConcurrentHashSet();
309         ExecutorService executor = Executors.newCachedThreadPool("requestIdsConcurrently()", LOG);
310         AtomicReference<Throwable> exceptionInExecutorAtomic = new AtomicReference<>();
311         for (int i = 0; i < numberOfTasks; i++) {
312             final String idKey;
313             if (isSameKey) {
314                 idKey = TEST_KEY1;
315             } else {
316                 idKey = TEST_KEY1 + i;
317             }
318             executor.execute(() -> {
319                 // Any exception thrown inside this background thread will not cause the test to fail
320                 // so you cannot use assert* here but must set the exceptionInExecutor which is checked after
321                 Future<RpcResult<AllocateIdOutput>> result;
322                 result = idManagerService.allocateId(
323                         new AllocateIdInputBuilder().setPoolName(ID_POOL_NAME).setIdKey(idKey).build());
324                 try {
325                     if (result.get().isSuccessful()) {
326                         Long idValue = result.get().getResult().getIdValue();
327                         idSet.add(idValue);
328                         if (idValue > ID_LOW + BLOCK_SIZE) {
329                             exceptionInExecutorAtomic.set(new AssertionFailedError("idValue <= ID_LOW + BLOCK_SIZE"));
330                         }
331                     } else {
332                         RpcError error = result.get().getErrors().iterator().next();
333                         if (!error.getCause().getMessage().contains("Ids exhausted for pool : " + ID_POOL_NAME)) {
334                             exceptionInExecutorAtomic.set(error.getCause());
335                         }
336                     }
337                 } catch (InterruptedException | ExecutionException e) {
338                     exceptionInExecutorAtomic.set(e);
339                 } finally {
340                     latch.countDown();
341                 }
342             });
343         }
344         if (!latch.await(13, SECONDS)) {
345             fail("latch.await(13, SECONDS) timed out :(");
346         }
347         Throwable exceptionInExecutor = exceptionInExecutorAtomic.get();
348         if (exceptionInExecutor != null) {
349             throw exceptionInExecutor;
350         }
351         if (isSameKey) {
352             assertEquals(1, idSet.size());
353         } else {
354             assertEquals(numberOfTasks, idSet.size());
355         }
356     }
357
358     private InstanceIdentifier<IdPool> getIdPoolIdentifier(String poolName) {
359         InstanceIdentifier.InstanceIdentifierBuilder<IdPool> idBuilder =
360                 InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(poolName));
361         return idBuilder.build();
362     }
363
364     private ReleasedIdsHolder createReleaseIdHolder(List<Long> delayedIds) {
365         List<DelayedIdEntries> delayedIdEntries = new ArrayList<>();
366         for (Long id : delayedIds) {
367             delayedIdEntries.add(new DelayedIdEntriesBuilder().setId(id).setReadyTimeSec(0L).build());
368         }
369         return new ReleasedIdsHolderBuilder().setDelayedIdEntries(delayedIdEntries)
370                 .setAvailableIdCount((long) delayedIds.size()).build();
371     }
372
373     private AvailableIdsHolder createAvailableIdHolder(long start, long end, long cursor) {
374         return new AvailableIdsHolderBuilder().setStart(start).setEnd(end).setCursor(cursor).build();
375     }
376
377     private void validateIdPools(IdPool expectedIdPoolParent, IdPool expectedIdPoolChild)
378             throws ReadFailedException, ComparisonFailure {
379         IdPool actualIdPoolParent = getUpdatedActualParentPool();
380         IdPool actualIdPoolChild = getUpdatedActualChildPool();
381
382         assertNotNull(actualIdPoolParent);
383         assertNotNull(actualIdPoolChild);
384         AssertDataObjects.assertEqualBeans(expectedIdPoolParent, actualIdPoolParent);
385         AssertDataObjects.assertEqualBeans(expectedIdPoolChild, actualIdPoolChild);
386
387     }
388
389     private IdPool getUpdatedActualChildPool() throws ReadFailedException {
390         String localPoolName = idUtils.getLocalPoolName(ID_POOL_NAME);
391         IdPool idPoolChildFromDS = singleTxdataBroker.syncRead(LogicalDatastoreType.CONFIGURATION,
392                 InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(localPoolName)).build());
393         List<DelayedIdEntries> actualDelayedIdEntries = idPoolChildFromDS.getReleasedIdsHolder().getDelayedIdEntries();
394         IdPool actualIdPoolChild = idPoolChildFromDS;
395         if (actualDelayedIdEntries != null) {
396             List<DelayedIdEntries> updatedDelayedIdEntries = actualDelayedIdEntries.stream()
397                     .map(delayedIdEntry -> new DelayedIdEntriesBuilder().setId(delayedIdEntry.getId())
398                             .setReadyTimeSec(0L).build())
399                     .collect(Collectors.toList());
400             ReleasedIdsHolder releasedId = new ReleasedIdsHolderBuilder(idPoolChildFromDS.getReleasedIdsHolder())
401                     .setDelayedIdEntries(updatedDelayedIdEntries).build();
402             actualIdPoolChild = new IdPoolBuilder(idPoolChildFromDS).setReleasedIdsHolder(releasedId).build();
403         }
404         return actualIdPoolChild;
405     }
406
407     private IdPool getUpdatedActualParentPool() throws ReadFailedException {
408         IdPool idPoolParentFromDS = singleTxdataBroker.syncRead(LogicalDatastoreType.CONFIGURATION,
409                 InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(ID_POOL_NAME)).build());
410         List<ChildPools> childPool = nullToEmpty(idPoolParentFromDS.getChildPools());
411         List<ChildPools> updatedChildPool = childPool.stream()
412                 .map(child -> new ChildPoolsBuilder(child).setLastAccessTime(0L).build()).collect(Collectors.toList());
413         List<IdEntries> idEntries = idPoolParentFromDS.getIdEntries();
414         IdPoolBuilder idPoolBuilder = new IdPoolBuilder(idPoolParentFromDS);
415         if (idEntries != null) {
416             List<IdEntries> sortedIdEntries = idEntries.stream().sorted(comparing(IdEntries::getIdKey))
417                     .collect(Collectors.toList());
418             idPoolBuilder.setIdEntries(sortedIdEntries);
419         }
420         return idPoolBuilder.setChildPools(updatedChildPool).build();
421     }
422 }