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    *      https://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  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertFalse;
21  import static org.junit.jupiter.api.Assertions.assertNotNull;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  
24  import java.time.Duration;
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.concurrent.ExecutorService;
28  import java.util.concurrent.Executors;
29  import java.util.concurrent.Future;
30  import java.util.concurrent.atomic.AtomicBoolean;
31  
32  import org.apache.commons.pool2.PooledObject;
33  import org.junit.jupiter.api.Test;
34  
35  /**
36   * Tests {@link DefaultPooledObject}.
37   */
38  class TestDefaultPooledObject {
39  
40      /**
41       * JIRA: POOL-279
42       *
43       * @throws Exception May occur in some failure modes
44       */
45      @Test
46      void testGetIdleTimeMillis() throws Exception {
47          final DefaultPooledObject<Object> dpo = new DefaultPooledObject<>(new Object());
48          final AtomicBoolean negativeIdleTimeReturned = new AtomicBoolean();
49          final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 3);
50          final Runnable allocateAndDeallocateTask = () -> {
51              for (int i1 = 0; i1 < 10000; i1++) {
52                  if (dpo.getIdleDuration().isNegative() || dpo.getIdleTime().isNegative() || dpo.getIdleDuration().isNegative()
53                          || dpo.getIdleTime().isNegative()) {
54                      negativeIdleTimeReturned.set(true);
55                      break;
56                  }
57              }
58              dpo.allocate();
59              for (int i2 = 0; i2 < 10000; i2++) {
60                  if (dpo.getIdleDuration().isNegative() || dpo.getIdleTime().isNegative()) {
61                      negativeIdleTimeReturned.set(true);
62                      break;
63                  }
64              }
65              dpo.deallocate();
66          };
67          final Runnable getIdleTimeTask = () -> {
68              for (int i = 0; i < 10000; i++) {
69                  if (dpo.getIdleDuration().isNegative() || dpo.getIdleTime().isNegative()) {
70                      negativeIdleTimeReturned.set(true);
71                      break;
72                  }
73              }
74          };
75          final double probabilityOfAllocationTask = 0.7;
76          final List<Future<?>> futures = new ArrayList<>();
77          for (int i = 1; i <= 10000; i++) {
78              final Runnable randomTask = Math.random() < probabilityOfAllocationTask ? allocateAndDeallocateTask : getIdleTimeTask;
79              futures.add(executor.submit(randomTask));
80          }
81          for (final Future<?> future : futures) {
82              future.get();
83          }
84          assertFalse(negativeIdleTimeReturned.get(), "DefaultPooledObject.getIdleTimeMillis() returned a negative value");
85      }
86  
87      @Test
88      void testInitialStateActiveDuration() throws InterruptedException {
89          final PooledObject<Object> dpo = new DefaultPooledObject<>(new Object());
90          // Sleep MUST be "long enough" to test that we are not returning a negative time.
91          // Need an API in Java 8 to get the clock granularity.
92          Thread.sleep(200);
93          // In the initial state, all instants are the creation instant: last borrow, last use, last return.
94          // In the initial state, the active duration is the time between "now" and the creation time.
95          // In the initial state, the idle duration is the time between "now" and the last return, which is the creation time.
96          assertFalse(dpo.getActiveDuration().isNegative());
97          assertFalse(dpo.getActiveDuration().isZero());
98          // We use greaterThanOrEqualTo instead of equal because "now" many be different when each argument is evaluated.
99          assertTrue(Duration.ZERO.compareTo(Duration.ZERO.plusNanos(1)) <= 0);
100         assertTrue(dpo.getActiveDuration().compareTo(dpo.getIdleDuration()) <= 0);
101         // Deprecated
102         assertTrue(dpo.getActiveDuration().toMillis() <= dpo.getActiveTimeMillis());
103         assertTrue(dpo.getActiveDuration().compareTo(dpo.getActiveTime()) <= 0);
104         assertTrue(dpo.getActiveDuration().compareTo(dpo.getIdleTime()) <= 0);
105         assertTrue(dpo.getActiveDuration().toMillis() <= dpo.getIdleTimeMillis());
106     }
107 
108     @Test
109     void testInitialStateCreateInstant() {
110         final PooledObject<Object> dpo = new DefaultPooledObject<>(new Object());
111 
112         // In the initial state, all instants are the creation instant: last borrow, last use, last return.
113 
114         // Instant vs. Instant
115         assertEquals(dpo.getCreateInstant(), dpo.getLastBorrowInstant());
116         assertEquals(dpo.getCreateInstant(), dpo.getLastReturnInstant());
117         assertEquals(dpo.getCreateInstant(), dpo.getLastUsedInstant());
118 
119         // Instant vs. long (deprecated)
120         assertEquals(dpo.getCreateInstant().toEpochMilli(), dpo.getCreateTime());
121 
122         // long vs. long (deprecated)
123         assertEquals(dpo.getCreateTime(), dpo.getLastBorrowTime());
124         assertEquals(dpo.getCreateTime(), dpo.getLastReturnTime());
125         assertEquals(dpo.getCreateTime(), dpo.getLastUsedTime());
126     }
127 
128     @Test
129     void testInitialStateDuration() throws InterruptedException {
130         final PooledObject<Object> dpo = new DefaultPooledObject<>(new Object());
131         final Duration duration1 = dpo.getFullDuration();
132         assertNotNull(duration1);
133         assertFalse(duration1.isNegative());
134         Thread.sleep(100);
135         final Duration duration2 = dpo.getFullDuration();
136         assertNotNull(duration2);
137         assertFalse(duration2.isNegative());
138         assertTrue(duration1.compareTo(duration2) < 0);
139     }
140 
141     @Test
142     void testInitialStateIdleDuration() throws InterruptedException {
143         final PooledObject<Object> dpo = new DefaultPooledObject<>(new Object());
144         // Sleep MUST be "long enough" to test that we are not returning a negative time.
145         Thread.sleep(200);
146         // In the initial state, all instants are the creation instant: last borrow, last use, last return.
147         // In the initial state, the active duration is the time between "now" and the creation time.
148         // In the initial state, the idle duration is the time between "now" and the last return, which is the creation time.
149         assertFalse(dpo.getIdleDuration().isNegative());
150         assertFalse(dpo.getIdleDuration().isZero());
151         // We use greaterThanOrEqualTo instead of equal because "now" many be different when each argument is evaluated.
152         assertTrue(dpo.getIdleDuration().compareTo(dpo.getActiveDuration()) <= 0);
153         // Deprecated
154         // assertThat(dpo.getIdleDuration().toMillis(), lessThanOrEqualTo(dpo.getIdleTimeMillis()));
155         // assertThat(dpo.getIdleDuration(), lessThanOrEqualTo(dpo.getIdleTime()));
156         assertTrue(dpo.getIdleDuration().compareTo(dpo.getActiveTime()) <= 0);
157         assertTrue(dpo.getIdleDuration().toMillis() <= dpo.getActiveTimeMillis());
158     }
159 }