Initial OpenECOMP APPC commit
[appc.git] / app-c / appc / appc-common / src / test / java / org / openecomp / appc / pool / PoolTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : APP-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                                              reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  * 
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  * 
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22
23
24 package org.openecomp.appc.pool;
25
26 import static org.junit.Assert.assertEquals;
27 import static org.junit.Assert.assertFalse;
28 import static org.junit.Assert.assertNotNull;
29 import static org.junit.Assert.assertNull;
30 import static org.junit.Assert.assertTrue;
31
32 import java.io.IOException;
33 import java.lang.reflect.InvocationTargetException;
34 import java.lang.reflect.Method;
35 import java.lang.reflect.Proxy;
36
37 import org.junit.Before;
38 import org.junit.Test;
39 import org.openecomp.appc.pool.Allocator;
40 import org.openecomp.appc.pool.Destructor;
41 import org.openecomp.appc.pool.Pool;
42 import org.openecomp.appc.pool.PoolDrainedException;
43 import org.openecomp.appc.pool.PoolExtensionException;
44 import org.openecomp.appc.pool.PoolSpecificationException;
45 import org.openecomp.appc.pool.*;
46
47
48 public class PoolTest implements Allocator<Testable>, Destructor<Testable> {
49
50     private Pool<Testable> pool;
51     private static final int MIN = 10;
52     private static final int MAX = 100;
53     private int index = 0;
54     private int destroyCount = 0;
55
56     /**
57      * Set up the test by allocating a pool with MIN-MAX size (bounded pool)
58      *
59      * @throws PoolSpecificationException
60      *             If the minimum size is less than 0, or if the max size is non-zero and less than the min size.
61      */
62     @Before
63     public void setup() throws PoolSpecificationException {
64         pool = new Pool<>(MIN, MAX);
65         index = 0;
66         destroyCount = 0;
67     }
68
69     /**
70      * Test that trying to construct a pool with a bad minimum throws an exception
71      *
72      * @throws PoolSpecificationException
73      *             If the minimum size is less than 0, or if the max size is non-zero and less than the min size.
74      */
75     @Test(expected = PoolSpecificationException.class)
76     public void testInvalidMinSize() throws PoolSpecificationException {
77         pool = new Pool<>(-1, MAX);
78     }
79
80     /**
81      * Test that trying to construct a pool with a bad maximum throws an exception
82      *
83      * @throws PoolSpecificationException
84      *             If the minimum size is less than 0, or if the max size is non-zero and less than the min size.
85      */
86     @Test(expected = PoolSpecificationException.class)
87     public void testInvalidMaxSize() throws PoolSpecificationException {
88         pool = new Pool<>(MIN, -1);
89     }
90
91     /**
92      * Test creation of a pool where max is less than min fails
93      *
94      * @throws PoolSpecificationException
95      *             If the minimum size is less than 0, or if the max size is non-zero and less than the min size.
96      */
97     @Test(expected = PoolSpecificationException.class)
98     public void testInvalidSizeRange() throws PoolSpecificationException {
99         pool = new Pool<>(MAX, MIN);
100     }
101
102     /**
103      * Test state
104      */
105     @Test
106     public void testMinPool() {
107         assertEquals(MIN, pool.getMinPool());
108     }
109
110     /**
111      * Test state
112      */
113     @Test
114     public void testMaxPool() {
115         assertEquals(MAX, pool.getMaxPool());
116     }
117
118     /**
119      * Test state
120      */
121     @Test
122     public void testAllocator() {
123         assertNull(pool.getAllocator());
124         pool.setAllocator(this);
125         assertNotNull(pool.getAllocator());
126     }
127
128     /**
129      * Test state
130      */
131     @Test
132     public void testDestructor() {
133         assertNull(pool.getDestructor());
134         pool.setDestructor(this);
135         assertNotNull(pool.getDestructor());
136     }
137
138     /**
139      * Test that we can allocate and release elements and that the pool maintains them in MRU order
140      *
141      * @throws PoolExtensionException
142      *             If the pool cannot be extended
143      * @throws PoolDrainedException
144      *             If the caller is trying to reserve an element from a drained pool
145      */
146     @Test
147     public void testAllocateAndRelease() throws PoolExtensionException, PoolDrainedException {
148         pool.setAllocator(this);
149
150         assertFalse(pool.isDrained());
151
152         /*
153          * Allocate three elements
154          */
155         Testable value1 = pool.reserve();
156         assertNotNull(value1);
157         assertEquals(Integer.valueOf(MIN - 1), value1.getId());
158         assertEquals(1, pool.getAllocatedSize());
159         assertEquals(MIN - 1, pool.getFreeSize());
160         assertEquals(1, pool.getAllocatedSize());
161
162         Testable value2 = pool.reserve();
163         assertNotNull(value2);
164         assertEquals(Integer.valueOf(MIN - 2), value2.getId());
165         assertEquals(2, pool.getAllocatedSize());
166         assertEquals(MIN - 2, pool.getFreeSize());
167         assertEquals(2, pool.getAllocatedSize());
168
169         Testable value3 = pool.reserve();
170         assertNotNull(value3);
171         assertEquals(Integer.valueOf(MIN - 3), value3.getId());
172         assertEquals(3, pool.getAllocatedSize());
173         assertEquals(MIN - 3, pool.getFreeSize());
174         assertEquals(3, pool.getAllocatedSize());
175
176         /*
177          * Now, release them in the order obtained
178          */
179         pool.release(value1);
180         pool.release(value2);
181         pool.release(value3);
182
183         assertEquals(0, pool.getAllocatedSize());
184         assertEquals(MIN, pool.getFreeSize());
185
186         /*
187          * Now, allocate them again, but their values should be reversed (3, 2, 1) representing the most recently used
188          * to the least recently used.
189          */
190         value1 = pool.reserve();
191         assertNotNull(value1);
192         assertEquals(Integer.valueOf(MIN - 3), value1.getId());
193
194         value2 = pool.reserve();
195         assertNotNull(value2);
196         assertEquals(Integer.valueOf(MIN - 2), value2.getId());
197
198         value3 = pool.reserve();
199         assertNotNull(value3);
200         assertEquals(Integer.valueOf(MIN - 1), value3.getId());
201     }
202
203     /**
204      * Test that we can trim the pool to a desired size
205      *
206      * @throws PoolExtensionException
207      *             If the pool cannot be extended
208      * @throws NoSuchMethodException
209      *             if a matching method is not found.
210      * @throws SecurityException
211      *             if the request is denied.
212      * @throws IllegalAccessException
213      *             if this Method object is enforcing Java language access control and the underlying method is
214      *             inaccessible.
215      * @throws IllegalArgumentException
216      *             if the method is an instance method and the specified object argument is not an instance of the class
217      *             or interface declaring the underlying method (or of a subclass or implementor thereof); if the number
218      *             of actual and formal parameters differ; if an unwrapping conversion for primitive arguments fails; or
219      *             if, after possible unwrapping, a parameter value cannot be converted to the corresponding formal
220      *             parameter type by a method invocation conversion.
221      * @throws InvocationTargetException
222      *             if the underlying method throws an exception.
223      * @throws PoolDrainedException
224      *             If the caller is trying to reserve an element from a drained pool
225      */
226     @SuppressWarnings("nls")
227     @Test
228     public void testTrim() throws PoolExtensionException, NoSuchMethodException, SecurityException,
229         IllegalAccessException, IllegalArgumentException, InvocationTargetException, PoolDrainedException {
230         pool.setAllocator(this);
231         int SIZE = 50;
232         Proxy[] array = new Proxy[SIZE];
233
234         assertEquals(0, pool.getAllocatedSize());
235         for (int i = 0; i < SIZE; i++) {
236             array[i] = (Proxy) pool.reserve();
237         }
238         assertEquals(SIZE, pool.getAllocatedSize());
239
240         for (int i = 0; i < SIZE; i++) {
241             pool.release((Testable) array[i]);
242         }
243         assertEquals(0, pool.getAllocatedSize());
244
245         assertEquals(SIZE, pool.getFreeSize());
246
247         Method trimMethod = Pool.class.getDeclaredMethod("trim", new Class[] {
248             Integer.TYPE
249         });
250         trimMethod.setAccessible(true);
251         trimMethod.invoke(pool, new Object[] {
252             SIZE - MIN
253         });
254
255         assertEquals(MIN, pool.getFreeSize());
256     }
257
258     /**
259      * Test that we can drain a pool containing a mix of free and allocated elements
260      *
261      * @throws PoolExtensionException
262      *             If the pool cannot be extended
263      * @throws PoolDrainedException
264      *             If the caller is trying to reserve an element from a drained pool
265      */
266     @Test
267     public void testDrain() throws PoolExtensionException, PoolDrainedException {
268         int SIZE = 50;
269         int FREE = 20;
270         int ALLOC = SIZE - FREE;
271
272         Proxy[] array = new Proxy[SIZE];
273         pool.setAllocator(this);
274         pool.setDestructor(this);
275
276         assertFalse(pool.isDrained());
277
278         assertEquals(0, pool.getAllocatedSize());
279         for (int i = 0; i < SIZE; i++) {
280             array[i] = (Proxy) pool.reserve();
281         }
282         assertEquals(SIZE, pool.getAllocatedSize());
283
284         for (int i = 0; i < FREE; i++) {
285             pool.release((Testable) array[i]);
286         }
287         assertEquals(ALLOC, pool.getAllocatedSize());
288         assertEquals(FREE, pool.getFreeSize());
289
290         pool.drain();
291         assertEquals(0, pool.getFreeSize());
292         assertEquals(0, pool.getAllocatedSize());
293         assertTrue(pool.isDrained());
294
295         assertEquals(SIZE, destroyCount);
296     }
297
298     /**
299      * @see org.openecomp.appc.pool.Destructor#destroy(java.io.Closeable, org.openecomp.appc.pool.Pool)
300      */
301     @Override
302     public void destroy(Testable obj, Pool<Testable> pool) {
303         destroyCount++;
304         try {
305             obj.close();
306         } catch (IOException e) {
307             e.printStackTrace();
308         }
309     }
310
311     /**
312      * @see org.openecomp.appc.pool.Allocator#allocate(org.openecomp.appc.pool.Pool)
313      */
314     @Override
315     public Testable allocate(Pool<Testable> pool) {
316         Testable e = new Element(index++);
317
318         return e;
319     }
320 }