View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.pool2.impl;
18  
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertNull;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  
25  import java.lang.reflect.Field;
26  import java.util.concurrent.ScheduledFuture;
27  import java.util.concurrent.ThreadPoolExecutor;
28  
29  import org.apache.commons.pool2.BasePooledObjectFactory;
30  import org.apache.commons.pool2.PooledObject;
31  import org.junit.jupiter.api.Test;
32  
33  /**
34   * Tests for {@link EvictionTimer}.
35   */
36  public class TestEvictionTimer {
37  
38      @Test
39      public void testStartStopEvictionTimer() throws Exception {
40  
41          try (final GenericObjectPool<String> pool = new GenericObjectPool<>(new BasePooledObjectFactory<String>() {
42  
43              @Override
44              public String create() {
45                  return null;
46              }
47  
48              @Override
49              public PooledObject<String> wrap(final String obj) {
50                  return new DefaultPooledObject<>(obj);
51              }
52          })) {
53  
54              // Start evictor #1
55              final BaseGenericObjectPool<String>.Evictor evictor1 = pool.new Evictor();
56              EvictionTimer.schedule(evictor1, TestConstants.ONE_MINUTE_DURATION, TestConstants.ONE_MINUTE_DURATION);
57  
58              // Assert that eviction objects are correctly allocated
59              // 1 - the evictor timer task is created
60              final Field evictorTaskFutureField =
61                      evictor1.getClass().getDeclaredField("scheduledFuture");
62              evictorTaskFutureField.setAccessible(true);
63              ScheduledFuture<?> sf = (ScheduledFuture<?>) evictorTaskFutureField.get(evictor1);
64              assertFalse(sf.isCancelled());
65              // 2- and, the eviction action is added to executor thread pool
66              final Field evictorExecutorField = EvictionTimer.class.getDeclaredField("executor");
67              evictorExecutorField.setAccessible(true);
68              final ThreadPoolExecutor evictionExecutor = (ThreadPoolExecutor) evictorExecutorField.get(null);
69              assertEquals(2, evictionExecutor.getQueue().size()); // Reaper plus one eviction task
70              assertEquals(1, EvictionTimer.getNumTasks());
71  
72              // Start evictor #2
73              final BaseGenericObjectPool<String>.Evictor evictor2 = pool.new Evictor();
74              EvictionTimer.schedule(evictor2, TestConstants.ONE_MINUTE_DURATION, TestConstants.ONE_MINUTE_DURATION);
75  
76              // Assert that eviction objects are correctly allocated
77              // 1 - the evictor timer task is created
78              sf = (ScheduledFuture<?>) evictorTaskFutureField.get(evictor2);
79              assertFalse(sf.isCancelled());
80              // 2- and, the eviction action is added to executor thread pool
81              assertEquals(3, evictionExecutor.getQueue().size()); // Reaper plus 2 eviction tasks
82              assertEquals(2, EvictionTimer.getNumTasks());
83  
84              // Stop evictor #1
85              EvictionTimer.cancel(evictor1, BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT, false);
86  
87              // Assert that eviction objects are correctly cleaned
88              // 1 - the evictor timer task is cancelled
89              sf = (ScheduledFuture<?>) evictorTaskFutureField.get(evictor1);
90              assertTrue(sf.isCancelled());
91              // 2- and, the eviction action is removed from executor thread pool
92              final ThreadPoolExecutor evictionExecutorOnStop = (ThreadPoolExecutor) evictorExecutorField.get(null);
93              assertEquals(2, evictionExecutorOnStop.getQueue().size());
94              assertEquals(1, EvictionTimer.getNumTasks());
95  
96              // Stop evictor #2
97              EvictionTimer.cancel(evictor2, BaseObjectPoolConfig.DEFAULT_EVICTOR_SHUTDOWN_TIMEOUT, false);
98  
99              // Assert that eviction objects are correctly cleaned
100             // 1 - the evictor timer task is cancelled
101             sf = (ScheduledFuture<?>) evictorTaskFutureField.get(evictor2);
102             assertTrue(sf.isCancelled());
103             // 2- and, the eviction thread pool executor is freed
104             assertNull(evictorExecutorField.get(null));
105             assertEquals(0, EvictionTimer.getNumTasks());
106         }
107     }
108 }