2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.genius.idmanager.test;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertTrue;
12 import static org.mockito.Matchers.any;
13 import static org.mockito.Matchers.anyObject;
14 import static org.mockito.Matchers.eq;
15 import static org.mockito.Mockito.doAnswer;
16 import static org.mockito.Mockito.doReturn;
17 import static org.mockito.Mockito.when;
19 import com.google.common.base.Optional;
20 import com.google.common.util.concurrent.Futures;
22 import java.net.UnknownHostException;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.List;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.CopyOnWriteArraySet;
29 import java.util.concurrent.CountDownLatch;
30 import java.util.concurrent.ExecutionException;
31 import java.util.concurrent.ExecutorService;
32 import java.util.concurrent.Executors;
33 import java.util.concurrent.Future;
34 import java.util.concurrent.TimeUnit;
36 import org.junit.Before;
37 import org.junit.Ignore;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 import org.mockito.Matchers;
41 import org.mockito.Mock;
42 import org.mockito.runners.MockitoJUnitRunner;
43 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
44 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
45 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
46 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
47 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
48 import org.opendaylight.genius.idmanager.IdLocalPool;
49 import org.opendaylight.genius.idmanager.IdManager;
50 import org.opendaylight.genius.idmanager.IdUtils;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInputBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdPools;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdPoolsBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPool;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolderBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPools;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPoolsBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPoolsKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntries;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntriesBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntriesKey;
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.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockInput;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInput;
80 import org.opendaylight.yangtools.yang.binding.DataObject;
81 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
82 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
83 import org.opendaylight.yangtools.yang.common.RpcError;
84 import org.opendaylight.yangtools.yang.common.RpcResult;
85 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
87 @RunWith(MockitoJUnitRunner.class)
88 public class IdManagerTest {
90 ConcurrentHashMap<InstanceIdentifier<?>, DataObject> configDataStore = new ConcurrentHashMap<>();
91 @Mock DataBroker dataBroker;
92 @Mock ReadOnlyTransaction mockReadTx;
93 @Mock WriteTransaction mockWriteTx;
94 @Mock LockManagerService lockManager;
95 Future<RpcResult<Void>> rpcResult;
99 String allocateIdPoolName = "allocateIdTest";
100 InstanceIdentifier<IdPool> parentPoolIdentifier;
101 InstanceIdentifier<IdPool> localPoolIdentifier;
102 InstanceIdentifier<ChildPools> childPoolIdentifier;
103 final String poolName = "test-pool";
107 String idKey = "test-key";
108 String localPoolName;
112 public void setUp() throws Exception {
113 idUtils = new IdUtils();
114 localPoolName = idUtils.getLocalPoolName(poolName);
116 parentPoolIdentifier = buildInstanceIdentifier(poolName);
117 localPoolIdentifier = buildInstanceIdentifier(localPoolName);
118 childPoolIdentifier = buildChildPoolInstanceIdentifier(poolName, localPoolName);
121 private void setupMocks(List<IdPool> idPools) throws ReadFailedException, UnknownHostException {
122 when(dataBroker.newReadOnlyTransaction()).thenReturn(mockReadTx);
123 when(dataBroker.newWriteOnlyTransaction()).thenReturn(mockWriteTx);
124 when(lockManager.lock(any(LockInput.class)))
125 .thenReturn(Futures.immediateFuture(RpcResultBuilder.<Void>success().build()));
126 when(lockManager.unlock(any(UnlockInput.class)))
127 .thenReturn(Futures.immediateFuture(RpcResultBuilder.<Void>success().build()));
128 doReturn(Futures.immediateCheckedFuture(null)).when(mockWriteTx).submit();
129 doAnswer(invocation -> {
130 configDataStore.put(invocation.getArgumentAt(1, KeyedInstanceIdentifier.class),
131 invocation.getArgumentAt(2, IdPool.class));
133 }).when(mockWriteTx).put(eq(LogicalDatastoreType.CONFIGURATION), Matchers.any(), Matchers.any(), eq(true));
134 doAnswer(invocation -> {
135 configDataStore.put(invocation.getArgumentAt(1, KeyedInstanceIdentifier.class),
136 invocation.getArgumentAt(2, IdPool.class));
138 }).when(mockWriteTx).merge(eq(LogicalDatastoreType.CONFIGURATION), Matchers.any(), Matchers.any(), eq(true));
139 doAnswer(invocation -> {
140 configDataStore.put(invocation.getArgumentAt(1, KeyedInstanceIdentifier.class),
141 invocation.getArgumentAt(2, IdPool.class));
143 }).when(mockWriteTx).merge(eq(LogicalDatastoreType.CONFIGURATION), Matchers.any(), Matchers.any());
144 doAnswer(invocation -> {
145 configDataStore.remove(invocation.getArgumentAt(1, KeyedInstanceIdentifier.class));
147 }).when(mockWriteTx).delete(eq(LogicalDatastoreType.CONFIGURATION), Matchers.<InstanceIdentifier<IdPool>>any());
149 doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(mockReadTx)
150 .read(eq(LogicalDatastoreType.CONFIGURATION), anyObject());
151 if (idPools != null && !idPools.isEmpty()) {
152 Optional<IdPools> optionalIdPools = Optional.of(new IdPoolsBuilder().setIdPool(idPools).build());
153 doReturn(Futures.immediateCheckedFuture(optionalIdPools)).when(mockReadTx)
154 .read(LogicalDatastoreType.CONFIGURATION, idUtils.getIdPools());
156 idManager = new IdManager(dataBroker, lockManager, idUtils);
160 public void testCreateIdPool() throws Exception {
162 CreateIdPoolInput createPoolTest = buildCreateIdPool(poolName, idStart, idEnd);
163 long expectedBlockSize = idUtils.computeBlockSize(idStart, idEnd);
165 Future<RpcResult<Void>> result = idManager.createIdPool(createPoolTest);
167 assertTrue(result.get().isSuccessful());
168 // Just to ensure the local pool is also written. Even if it is not triggered Test case will pass.
169 waitUntilJobIsDone();
170 assertTrue(configDataStore.size() > 0);
171 DataObject dataObject = configDataStore.get(localPoolIdentifier);
172 if (dataObject instanceof IdPool) {
173 pool = (IdPool) dataObject;
174 assertEquals(localPoolName, pool.getPoolName());
175 assertEquals(createPoolTest.getPoolName(), pool.getParentPoolName());
176 assertEquals(idStart, pool.getAvailableIdsHolder().getStart().intValue());
177 assertEquals(idStart + expectedBlockSize - 1, pool.getAvailableIdsHolder().getEnd().intValue());
178 assertEquals(idStart - 1, pool.getAvailableIdsHolder().getCursor().intValue());
179 assertEquals(30, pool.getReleasedIdsHolder().getDelayedTimeSec().longValue());
180 assertEquals(0, pool.getReleasedIdsHolder().getAvailableIdCount().longValue());
181 assertEquals(expectedBlockSize, pool.getBlockSize().longValue());
183 dataObject = configDataStore.get(parentPoolIdentifier);
184 if (dataObject instanceof IdPool) {
185 pool = (IdPool) dataObject;
186 assertEquals(createPoolTest.getPoolName(), pool.getPoolName());
187 assertEquals(0, pool.getReleasedIdsHolder().getDelayedTimeSec().longValue());
188 assertEquals(0, pool.getReleasedIdsHolder().getAvailableIdCount().longValue());
189 assertEquals(createPoolTest.getLow(), pool.getAvailableIdsHolder().getStart());
190 assertEquals(createPoolTest.getHigh(), pool.getAvailableIdsHolder().getEnd());
191 assertEquals(createPoolTest.getLow() - 1, pool.getAvailableIdsHolder().getCursor().intValue());
192 assertEquals(expectedBlockSize, pool.getBlockSize().longValue());
194 dataObject = configDataStore.get(childPoolIdentifier);
195 if (dataObject instanceof ChildPools) {
196 ChildPools childPool = (ChildPools) dataObject;
197 assertEquals(localPoolName, childPool.getChildPoolName());
202 public void testAllocateId() throws Exception {
203 List<IdPool> listOfIdPool = new ArrayList<>();
204 IdPool localIdPool = buildLocalIdPool(blockSize, idStart, idStart + blockSize - 1, idStart - 1, localPoolName,
206 listOfIdPool.add(localIdPool);
207 IdPool globalIdPool = buildGlobalIdPool(poolName, idStart, idEnd, idStart + blockSize,
208 buildChildPool(localPoolName)).build();
209 listOfIdPool.add(globalIdPool);
210 setupMocks(listOfIdPool);
211 doReturn(Futures.immediateCheckedFuture(Optional.of(globalIdPool))).when(mockReadTx).read(
212 LogicalDatastoreType.CONFIGURATION, parentPoolIdentifier);
214 AllocateIdInput allocateIdInput = buildAllocateId(poolName, idKey);
215 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(allocateIdInput);
216 assertTrue(result.get().isSuccessful());
217 waitUntilJobIsDone();
218 assertTrue(configDataStore.size() > 0);
219 DataObject dataObject = configDataStore.get(localPoolIdentifier);
220 if (dataObject instanceof IdPool) {
221 IdPool pool = (IdPool) dataObject;
222 assertEquals(localPoolName, pool.getPoolName());
223 assertEquals(idStart, pool.getAvailableIdsHolder().getStart().intValue());
224 assertEquals(idStart + blockSize - 1 , pool.getAvailableIdsHolder().getEnd().intValue());
225 assertEquals(idStart, pool.getAvailableIdsHolder().getCursor().intValue());
227 dataObject = configDataStore.get(parentPoolIdentifier);
228 if (dataObject instanceof IdPool) {
229 IdPool parentPool = (IdPool) dataObject;
230 assertEquals(1, parentPool.getIdEntries().size());
232 dataObject = configDataStore.get(childPoolIdentifier);
233 if (dataObject instanceof ChildPools) {
234 ChildPools childPool = (ChildPools) dataObject;
235 assertEquals(localPoolName, childPool.getChildPoolName());
240 public void testReleaseId() throws Exception {
241 List<IdEntries> idEntries = new ArrayList<>();
242 List<Long> idValuesList = new ArrayList<>();
243 idValuesList.add(idValue);
245 List<IdPool> listOfIdPool = new ArrayList<>();
246 IdPool expectedLocalPool = buildLocalIdPool(blockSize, idStart, idStart + blockSize - 1, idStart - 1,
247 localPoolName, poolName).build();
248 IdPool globalIdPool = buildGlobalIdPool(poolName, idStart, idEnd, blockSize, buildChildPool(localPoolName))
249 .setIdEntries(idEntries).build();
250 listOfIdPool.add(expectedLocalPool);
251 listOfIdPool.add(globalIdPool);
252 setupMocks(listOfIdPool);
253 doReturn(Futures.immediateCheckedFuture(Optional.of(globalIdPool))).when(mockReadTx).read(
254 LogicalDatastoreType.CONFIGURATION, parentPoolIdentifier);
256 InstanceIdentifier<IdEntries> idEntriesIdentifier = buildIdEntriesIdentifier(parentPoolIdentifier, idKey);
257 Optional<IdEntries> expectedIdEntry = Optional.of(buildIdEntry(idKey, idValuesList));
258 doReturn(Futures.immediateCheckedFuture(expectedIdEntry)).when(mockReadTx).read(
259 LogicalDatastoreType.CONFIGURATION, idEntriesIdentifier);
261 ReleaseIdInput releaseIdInput = createReleaseIdInput(poolName, idKey);
262 Future<RpcResult<Void>> result = idManager.releaseId(releaseIdInput);
263 assertTrue(result.get().isSuccessful());
264 waitUntilJobIsDone();
266 assertTrue(configDataStore.size() > 0);
267 DataObject dataObject = configDataStore.get(localPoolIdentifier);
268 if (dataObject instanceof IdPool) {
269 IdPool pool = (IdPool) dataObject;
270 assertEquals(1, pool.getReleasedIdsHolder().getAvailableIdCount().intValue());
271 assertEquals(idValue, pool.getReleasedIdsHolder().getDelayedIdEntries().get(0).getId().intValue());
273 dataObject = configDataStore.get(parentPoolIdentifier);
274 if (dataObject instanceof IdPool) {
275 IdPool parentPool = (IdPool) dataObject;
276 assertEquals(0, parentPool.getIdEntries().size());
278 dataObject = configDataStore.get(childPoolIdentifier);
279 if (dataObject instanceof ChildPools) {
280 ChildPools childPool = (ChildPools) dataObject;
281 assertEquals(localPoolName, childPool.getChildPoolName());
286 * Ignoring this test case since cleanup task gets scheduled only after 30
287 * seconds. Therefore in order to validate the pool state the test has to
288 * wait for at least 30 seconds.
291 public void testCleanupReleasedIds() throws Exception {
292 List<Long> idValues = Arrays.asList(1L, 2L, 3L, 4L, 5L);
293 IdEntries idEntry = buildIdEntry(idKey, idValues);
294 List<IdEntries> listOfIdEntries = new ArrayList<>();
295 listOfIdEntries.add(idEntry);
297 IdPool globalIdPool = buildGlobalIdPool(poolName, idStart, idEnd, blockSize, buildChildPool(localPoolName))
298 .setIdEntries(listOfIdEntries).build();
299 IdPool expectedLocalPool = buildLocalIdPool(blockSize, idStart, idStart + blockSize - 1, idStart - 1,
300 localPoolName, poolName).build();
301 List<IdPool> listOfIdPool = new ArrayList<>();
303 listOfIdPool.add(expectedLocalPool);
304 listOfIdPool.add(globalIdPool);
305 setupMocks(listOfIdPool);
307 Optional<IdPool> expectedGlobalPool = Optional.of(globalIdPool);
308 doReturn(Futures.immediateCheckedFuture(expectedGlobalPool)).when(mockReadTx).read(
309 LogicalDatastoreType.CONFIGURATION, parentPoolIdentifier);
311 InstanceIdentifier<IdEntries> idEntriesIdentifier = buildIdEntriesIdentifier(parentPoolIdentifier, idKey);
312 Optional<IdEntries> expectedIdEntry = Optional.of(idEntry);
313 doReturn(Futures.immediateCheckedFuture(expectedIdEntry)).when(mockReadTx).read(
314 LogicalDatastoreType.CONFIGURATION, idEntriesIdentifier);
316 ReleasedIdsHolder releaseIdsHolder = createReleasedIdsHolder(0, new ArrayList<>(), 0);
317 InstanceIdentifier<ReleasedIdsHolder> releaseHolderIdentifier = buildReleaseIdsIdentifier(poolName);
318 doReturn(Futures.immediateCheckedFuture(Optional.of(releaseIdsHolder))).when(mockReadTx).read(
319 LogicalDatastoreType.CONFIGURATION, releaseHolderIdentifier);
321 ReleaseIdInput releaseIdInput = createReleaseIdInput(poolName, idKey);
322 Future<RpcResult<Void>> result = idManager.releaseId(releaseIdInput);
324 assertTrue(result.get().isSuccessful());
325 assertTrue(configDataStore.size() > 0);
327 DataObject dataObject = configDataStore.get(localPoolIdentifier);
328 if (dataObject instanceof IdPool) {
329 IdPool pool = (IdPool) dataObject;
330 assertEquals(2, pool.getReleasedIdsHolder().getAvailableIdCount().intValue());
333 dataObject = configDataStore.get(parentPoolIdentifier);
334 if (dataObject instanceof IdPool) {
335 IdPool parentPool = (IdPool) dataObject;
336 assertEquals(0, parentPool.getIdEntries().size());
339 dataObject = configDataStore.get(childPoolIdentifier);
340 if (dataObject instanceof ChildPools) {
341 ChildPools childPool = (ChildPools) dataObject;
342 assertEquals(localPoolName, childPool.getChildPoolName());
345 InstanceIdentifier<ReleasedIdsHolder> releaseIdsIdentifier = buildReleaseIdsIdentifier(poolName);
346 dataObject = configDataStore.get(releaseIdsIdentifier);
347 if (dataObject instanceof ReleasedIdsHolder) {
348 ReleasedIdsHolder releasedIds = (ReleasedIdsHolder) dataObject;
349 assertEquals(3, releasedIds.getAvailableIdCount().intValue());
350 assertEquals(3, releasedIds.getDelayedIdEntries().size());
355 public void testAllocateIdBlockFromReleasedIds() throws Exception {
356 List<DelayedIdEntries> delayedIdEntries = buildDelayedIdEntries(new long[] {150, 151, 152});
357 ReleasedIdsHolder expectedReleasedIds = createReleasedIdsHolder(3, delayedIdEntries , 0);
358 IdPool globalIdPool = buildGlobalIdPool(poolName, idStart, idEnd, blockSize, buildChildPool(localPoolName))
359 .setReleasedIdsHolder(expectedReleasedIds).build();
360 IdPool localPool = buildLocalIdPool(blockSize, idStart, idStart + blockSize - 1, idStart + blockSize - 1,
361 localPoolName, poolName).build();
362 Optional<IdPool> expected = Optional.of(globalIdPool);
363 List<IdPool> listOfIdPool = new ArrayList<>();
364 listOfIdPool.add(localPool);
365 listOfIdPool.add(globalIdPool);
366 InstanceIdentifier<IdPool> parentPoolIdentifier = buildInstanceIdentifier(poolName);
367 doReturn(Futures.immediateCheckedFuture(expected)).when(mockReadTx).read(
368 LogicalDatastoreType.CONFIGURATION, parentPoolIdentifier);
370 setupMocks(listOfIdPool);
371 doReturn(Futures.immediateCheckedFuture(Optional.of(globalIdPool))).when(mockReadTx).read(
372 LogicalDatastoreType.CONFIGURATION, parentPoolIdentifier);
374 AllocateIdInput allocateIdInput = buildAllocateId(poolName, idKey);
375 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(allocateIdInput);
376 assertTrue(result.get().isSuccessful());
377 waitUntilJobIsDone();
379 assertTrue(configDataStore.size() > 0);
380 InstanceIdentifier<IdPool> localPoolIdentifier = buildInstanceIdentifier(localPoolName);
381 DataObject dataObject = configDataStore.get(localPoolIdentifier);
382 if (dataObject instanceof IdPool) {
383 IdPool pool = (IdPool) dataObject;
384 assertEquals(localPoolName, pool.getPoolName());
385 assertEquals(1, pool.getReleasedIdsHolder().getDelayedIdEntries().size());
386 assertEquals(1, pool.getReleasedIdsHolder().getAvailableIdCount().intValue());
389 InstanceIdentifier<ReleasedIdsHolder> releaseIdsIdentifier = buildReleaseIdsIdentifier(poolName);
390 dataObject = configDataStore.get(releaseIdsIdentifier);
391 if (dataObject instanceof ReleasedIdsHolder) {
392 ReleasedIdsHolder releasedIds = (ReleasedIdsHolder) dataObject;
393 assertEquals(1, releasedIds.getAvailableIdCount().intValue());
394 assertEquals(1, releasedIds.getDelayedIdEntries().size());
397 InstanceIdentifier<ChildPools> childPoolIdentifier = buildChildPoolInstanceIdentifier(poolName, localPoolName);
398 dataObject = configDataStore.get(childPoolIdentifier);
399 if (dataObject instanceof ChildPools) {
400 ChildPools childPool = (ChildPools) dataObject;
401 assertEquals(localPoolName, childPool.getChildPoolName());
406 public void testDeletePool() throws Exception {
407 IdPool globalIdPool = buildGlobalIdPool(poolName, idStart, idEnd, blockSize, buildChildPool(localPoolName))
409 IdPool localPool = buildLocalIdPool(blockSize, idStart, idStart + blockSize - 1, idStart + blockSize - 1,
410 localPoolName, poolName).build();
411 List<IdPool> listOfIdPool = new ArrayList<>();
412 listOfIdPool.add(localPool);
413 listOfIdPool.add(globalIdPool);
414 // Pre-loading the map so that we can remove it when it is removed from DS.
415 configDataStore.put(parentPoolIdentifier, globalIdPool);
416 configDataStore.put(localPoolIdentifier, localPool);
417 setupMocks(listOfIdPool);
418 Optional<IdPool> expected = Optional.of(globalIdPool);
419 doReturn(Futures.immediateCheckedFuture(expected)).when(mockReadTx).read(
420 LogicalDatastoreType.CONFIGURATION, parentPoolIdentifier);
421 DeleteIdPoolInput deleteIdPoolInput = createDeleteIdPoolInput(poolName);
422 Future<RpcResult<Void>> result = idManager.deleteIdPool(deleteIdPoolInput);
423 waitUntilJobIsDone();
424 assertTrue(result.get().isSuccessful());
425 assertTrue(configDataStore.size() == 0);
426 DataObject dataObject = configDataStore.get(localPoolIdentifier);
427 assertEquals(dataObject, null);
428 dataObject = configDataStore.get(parentPoolIdentifier);
429 assertEquals(dataObject, null);
433 public void testMultithreadedIdAllocationFromAvailableIds() throws Exception {
434 setupMockForMultiThreads(false);
435 int numberOfTasks = 3;
436 CountDownLatch latch = new CountDownLatch(numberOfTasks);
437 Set<Long> idSet = new CopyOnWriteArraySet<>();
438 requestIdsConcurrently(latch, numberOfTasks, idSet, false);
440 waitUntilJobIsDone();
441 DataObject dataObject = configDataStore.get(localPoolIdentifier);
442 if (dataObject instanceof IdPool) {
443 IdPool pool = (IdPool) dataObject;
444 assertTrue(idStart + blockSize - 1 <= pool.getAvailableIdsHolder().getCursor());
449 public void testMultithreadedIdAllocationFromReleasedIds() throws Exception {
450 setupMockForMultiThreads(true);
451 // Check if the available id count is 3.
452 java.util.Optional<IdLocalPool> idLocalPool = idManager.getIdLocalPool(poolName);
453 assertTrue(idLocalPool.isPresent());
454 assertTrue(idLocalPool.get().getReleasedIds().getAvailableIdCount() == 3);
455 int numberOfTasks = 3;
456 CountDownLatch latch = new CountDownLatch(numberOfTasks);
457 Set<Long> idSet = new CopyOnWriteArraySet<>();
458 requestIdsConcurrently(latch, numberOfTasks, idSet, false);
460 waitUntilJobIsDone();
461 // Check if the available id count is 0.
462 idLocalPool = idManager.getIdLocalPool(poolName);
463 assertTrue(idLocalPool.isPresent());
464 assertTrue(idLocalPool.get().getReleasedIds().getAvailableIdCount() == 0);
468 public void testMultithreadedIdAllocationForSameKeyFromAvailableIds() throws Exception {
469 setupMockForMultiThreads(false);
470 int numberOfTasks = 3;
471 CountDownLatch latch = new CountDownLatch(numberOfTasks);
472 Set<Long> idSet = new CopyOnWriteArraySet<>();
473 requestIdsConcurrently(latch, numberOfTasks, idSet, true);
475 assertTrue(idSet.size() == 1);
476 waitUntilJobIsDone();
477 DataObject dataObject = configDataStore.get(localPoolIdentifier);
478 if (dataObject instanceof IdPool) {
479 IdPool pool = (IdPool) dataObject;
480 assertTrue(idStart == pool.getAvailableIdsHolder().getCursor());
485 public void testMultithreadedIdAllocationForSameKeyFromReleasedIds() throws Exception {
486 setupMockForMultiThreads(true);
487 int numberOfTasks = 3;
488 CountDownLatch latch = new CountDownLatch(numberOfTasks);
489 Set<Long> idSet = new CopyOnWriteArraySet<>();
490 requestIdsConcurrently(latch, numberOfTasks, idSet, true);
492 assertTrue(idSet.size() == 1);
493 waitUntilJobIsDone();
494 DataObject dataObject = configDataStore.get(localPoolIdentifier);
495 if (dataObject instanceof IdPool) {
496 IdPool pool = (IdPool) dataObject;
497 assertTrue(pool.getReleasedIdsHolder().getAvailableIdCount() == 2);
501 private void setupMockForMultiThreads(boolean isRelease) throws ReadFailedException, UnknownHostException {
502 List<IdPool> listOfIdPool = new ArrayList<>();
503 IdPoolBuilder localIdPool =
504 buildLocalIdPool(blockSize, idStart, idStart + blockSize, idStart - 1,
505 localPoolName, poolName);
507 IdPool globalIdPool = buildGlobalIdPool(poolName, idStart, poolSize, blockSize,
508 buildChildPool(localPoolName)).build();
509 listOfIdPool.add(globalIdPool);
510 setupMocks(listOfIdPool);
511 doReturn(Futures.immediateCheckedFuture(Optional.of(globalIdPool))).when(mockReadTx).read(
512 LogicalDatastoreType.CONFIGURATION, parentPoolIdentifier);
514 List<DelayedIdEntries> delayedIdEntries = buildDelayedIdEntries(new long[] {100, 101, 102});
515 ReleasedIdsHolder expectedReleasedIds = createReleasedIdsHolder(3, delayedIdEntries , 0);
517 localIdPool.setReleasedIdsHolder(expectedReleasedIds);
519 listOfIdPool.add(localIdPool.build());
520 listOfIdPool.add(globalIdPool);
521 setupMocks(listOfIdPool);
522 doAnswer(invocation -> {
523 DataObject result = configDataStore.get(idUtils.getIdEntry(parentPoolIdentifier, idKey));
524 if (result == null) {
525 return Futures.immediateCheckedFuture(Optional.absent());
527 if (result instanceof IdEntries) {
528 return Futures.immediateCheckedFuture(Optional.of((IdEntries) result));
530 return Futures.immediateCheckedFuture(Optional.absent());
531 }).when(mockReadTx).read(LogicalDatastoreType.CONFIGURATION, idUtils.getIdEntry(parentPoolIdentifier, idKey));
533 doReturn(Futures.immediateCheckedFuture(Optional.of(globalIdPool))).when(mockReadTx).read(
534 LogicalDatastoreType.CONFIGURATION, parentPoolIdentifier);
537 private InstanceIdentifier<ReleasedIdsHolder> buildReleaseIdsIdentifier(
539 InstanceIdentifier<ReleasedIdsHolder> releasedIds = InstanceIdentifier
540 .builder(IdPools.class).child(IdPool.class,
541 new IdPoolKey(poolName)).child(ReleasedIdsHolder.class).build();
545 private InstanceIdentifier<ChildPools> buildChildPoolInstanceIdentifier(String poolName, String childPoolName) {
546 InstanceIdentifier<ChildPools> childPool = InstanceIdentifier
547 .builder(IdPools.class).child(IdPool.class,
548 new IdPoolKey(poolName)).child(ChildPools.class, new ChildPoolsKey(childPoolName)).build();
552 private ReleaseIdInput createReleaseIdInput(String poolName, String idKey) {
553 return new ReleaseIdInputBuilder().setIdKey(idKey).setPoolName(poolName).build();
556 private IdEntries buildIdEntry(String idKey, List<Long> idValuesList) {
557 return new IdEntriesBuilder().setIdKey(idKey).setIdValue(idValuesList).build();
560 private InstanceIdentifier<IdEntries> buildIdEntriesIdentifier(InstanceIdentifier<IdPool> identifier,
562 InstanceIdentifier.InstanceIdentifierBuilder<IdEntries> idEntriesBuilder = identifier
563 .builder().child(IdEntries.class, new IdEntriesKey(idKey));
564 InstanceIdentifier<IdEntries> idEntry = idEntriesBuilder.build();
568 private CreateIdPoolInput buildCreateIdPool(String poolName, long low, long high) {
569 CreateIdPoolInput createPool = new CreateIdPoolInputBuilder().setPoolName(poolName)
576 private IdPoolBuilder buildGlobalIdPool(String poolName, long idStart, long poolSize, int blockSize,
577 List<ChildPools> childPools) {
578 AvailableIdsHolder availableIdsHolder = createAvailableIdsHolder(idStart, poolSize, idStart - 1);
579 ReleasedIdsHolder releasedIdsHolder = createReleasedIdsHolder(0, null, 0);
580 return new IdPoolBuilder().setKey(new IdPoolKey(poolName))
581 .setPoolName(poolName)
582 .setBlockSize(blockSize)
583 .setChildPools(childPools)
584 .setAvailableIdsHolder(availableIdsHolder)
585 .setReleasedIdsHolder(releasedIdsHolder);
588 private IdPoolBuilder buildLocalIdPool(int blockSize, int start, int end, int cursor, String localPoolName,
589 String parentPoolName) {
590 ReleasedIdsHolder releasedIdsHolder = createReleasedIdsHolder(0, null, 30);
591 return new IdPoolBuilder().setBlockSize(blockSize)
592 .setKey(new IdPoolKey(localPoolName))
593 .setParentPoolName(parentPoolName)
594 .setReleasedIdsHolder(releasedIdsHolder)
595 .setAvailableIdsHolder(createAvailableIdsHolder(start, end, cursor));
598 private AllocateIdInput buildAllocateId(String poolName, String idKey) {
599 AllocateIdInput getIdInput = new AllocateIdInputBuilder().setPoolName(poolName)
600 .setIdKey(idKey).build();
604 private InstanceIdentifier<IdPool> buildInstanceIdentifier(String poolName) {
605 InstanceIdentifier.InstanceIdentifierBuilder<IdPool> idBuilder =
606 InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(poolName));
607 InstanceIdentifier<IdPool> id = idBuilder.build();
611 private AvailableIdsHolder createAvailableIdsHolder(long low, long high, long cursor) {
612 AvailableIdsHolder availableIdsHolder = new AvailableIdsHolderBuilder()
613 .setStart(low).setEnd(high).setCursor(cursor).build();
614 return availableIdsHolder;
617 private ReleasedIdsHolder createReleasedIdsHolder(long availableIdCount, List<DelayedIdEntries> delayedIdEntries,
619 ReleasedIdsHolder releasedIdsHolder = new ReleasedIdsHolderBuilder()
620 .setAvailableIdCount(availableIdCount)
621 .setDelayedIdEntries(delayedIdEntries)
622 .setDelayedTimeSec(delayTime).build();
623 return releasedIdsHolder;
626 private DeleteIdPoolInput createDeleteIdPoolInput(String poolName) {
627 return new DeleteIdPoolInputBuilder().setPoolName(poolName).build();
630 private List<DelayedIdEntries> buildDelayedIdEntries(long[] idValues) {
631 List<DelayedIdEntries> delayedIdEntriesList = new ArrayList<>();
632 for (long idValue : idValues) {
633 DelayedIdEntries delayedIdEntries = new DelayedIdEntriesBuilder().setId(idValue)
634 .setReadyTimeSec(0L).build();
635 delayedIdEntriesList.add(delayedIdEntries);
637 return delayedIdEntriesList;
640 private List<ChildPools> buildChildPool(String childPoolName) {
641 ChildPools childPools = new ChildPoolsBuilder().setChildPoolName(childPoolName)
642 .setLastAccessTime(System.currentTimeMillis() / 1000).build();
643 List<ChildPools> childPoolsList = new ArrayList<>();
644 childPoolsList.add(childPools);
645 return childPoolsList;
648 private void requestIdsConcurrently(CountDownLatch latch, int numberOfTasks, Set<Long> idSet, boolean isSameKey) {
649 ExecutorService executor = Executors.newCachedThreadPool();
650 for (int i = 0; i < numberOfTasks; i++) {
651 executor.execute(new Runnable() {
654 Future<RpcResult<AllocateIdOutput>> result;
656 result = idManager.allocateId(buildAllocateId(poolName,
657 Thread.currentThread().getName()));
659 result = idManager.allocateId(buildAllocateId(poolName,
663 if (result.get().isSuccessful()) {
664 Long idValue = result.get().getResult().getIdValue();
665 assertTrue(idValue <= idStart + blockSize);
669 assertTrue(idSet.add(idValue));
672 RpcError error = result.get().getErrors().iterator().next();
673 assertTrue(error.getCause().getMessage().contains("Ids exhausted for pool : " + poolName));
675 } catch (ExecutionException | InterruptedException e) {
676 assertTrue(e.getCause().getMessage(), false);
685 private void waitUntilJobIsDone() throws InterruptedException {
686 TimeUnit.SECONDS.sleep(1);