1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.client5.http.impl.classic;
28
29
30 import static org.junit.jupiter.api.Assertions.assertEquals;
31 import static org.junit.jupiter.api.Assertions.assertTrue;
32
33 import java.util.Random;
34
35 import org.apache.hc.client5.http.HttpRoute;
36 import org.apache.hc.client5.http.classic.BackoffManager;
37 import org.apache.hc.core5.http.HttpHost;
38 import org.apache.hc.core5.util.TimeValue;
39 import org.junit.jupiter.api.BeforeEach;
40 import org.junit.jupiter.api.Test;
41
42 public class TestAIMDBackoffManager {
43
44 private AIMDBackoffManager impl;
45 private MockConnPoolControl connPerRoute;
46 private HttpRoute route;
47 private MockClock clock;
48
49 @BeforeEach
50 public void setUp() {
51 connPerRoute = new MockConnPoolControl();
52 route = new HttpRoute(new HttpHost("localhost", 80));
53 clock = new MockClock();
54 impl = new AIMDBackoffManager(connPerRoute, clock);
55 impl.setPerHostConnectionCap(10);
56 }
57
58 @Test
59 public void isABackoffManager() {
60 assertTrue(impl instanceof BackoffManager);
61 }
62
63 @Test
64 public void halvesConnectionsOnBackoff() {
65 connPerRoute.setMaxPerRoute(route, 4);
66 impl.backOff(route);
67 assertEquals(2, connPerRoute.getMaxPerRoute(route));
68 }
69
70 @Test
71 public void doesNotBackoffBelowOneConnection() {
72 connPerRoute.setMaxPerRoute(route, 1);
73 impl.backOff(route);
74 assertEquals(1, connPerRoute.getMaxPerRoute(route));
75 }
76
77 @Test
78 public void increasesByOneOnProbe() {
79 connPerRoute.setMaxPerRoute(route, 2);
80 impl.probe(route);
81 assertEquals(3, connPerRoute.getMaxPerRoute(route));
82 }
83
84 @Test
85 public void doesNotIncreaseBeyondPerHostMaxOnProbe() {
86 connPerRoute.setDefaultMaxPerRoute(5);
87 connPerRoute.setMaxPerRoute(route, 5);
88 impl.setPerHostConnectionCap(5);
89 impl.probe(route);
90 assertEquals(5, connPerRoute.getMaxPerRoute(route));
91 }
92
93 @Test
94 public void backoffDoesNotAdjustDuringCoolDownPeriod() {
95 connPerRoute.setMaxPerRoute(route, 4);
96 final long now = System.currentTimeMillis();
97 clock.setCurrentTime(now);
98 impl.backOff(route);
99 final long max = connPerRoute.getMaxPerRoute(route);
100 clock.setCurrentTime(now + 1);
101 impl.backOff(route);
102 assertEquals(max, connPerRoute.getMaxPerRoute(route));
103 }
104
105 @Test
106 public void backoffStillAdjustsAfterCoolDownPeriod() {
107 connPerRoute.setMaxPerRoute(route, 8);
108 final long now = System.currentTimeMillis();
109 clock.setCurrentTime(now);
110 impl.backOff(route);
111 final long max = connPerRoute.getMaxPerRoute(route);
112 clock.setCurrentTime(now + 10 * 1000L);
113 impl.backOff(route);
114 assertTrue(max == 1 || max > connPerRoute.getMaxPerRoute(route));
115 }
116
117 @Test
118 public void probeDoesNotAdjustDuringCooldownPeriod() {
119 connPerRoute.setMaxPerRoute(route, 4);
120 final long now = System.currentTimeMillis();
121 clock.setCurrentTime(now);
122 impl.probe(route);
123 final long max = connPerRoute.getMaxPerRoute(route);
124 clock.setCurrentTime(now + 1);
125 impl.probe(route);
126 assertEquals(max, connPerRoute.getMaxPerRoute(route));
127 }
128
129 @Test
130 public void probeStillAdjustsAfterCoolDownPeriod() {
131 connPerRoute.setMaxPerRoute(route, 8);
132 final long now = System.currentTimeMillis();
133 clock.setCurrentTime(now);
134 impl.probe(route);
135 final long max = connPerRoute.getMaxPerRoute(route);
136 clock.setCurrentTime(now + 10 * 1000L);
137 impl.probe(route);
138 assertTrue(max < connPerRoute.getMaxPerRoute(route));
139 }
140
141 @Test
142 public void willBackoffImmediatelyEvenAfterAProbe() {
143 connPerRoute.setMaxPerRoute(route, 8);
144 final long now = System.currentTimeMillis();
145 clock.setCurrentTime(now);
146 impl.probe(route);
147 final long max = connPerRoute.getMaxPerRoute(route);
148 clock.setCurrentTime(now + 1);
149 impl.backOff(route);
150 assertTrue(connPerRoute.getMaxPerRoute(route) < max);
151 }
152
153 @Test
154 public void backOffFactorIsConfigurable() {
155 connPerRoute.setMaxPerRoute(route, 10);
156 impl.setBackoffFactor(0.9);
157 impl.backOff(route);
158 assertEquals(9, connPerRoute.getMaxPerRoute(route));
159 }
160
161 @Test
162 public void coolDownPeriodIsConfigurable() {
163 long cd = new Random().nextLong() / 2;
164 if (cd < 0) {
165 cd *= -1;
166 }
167 if (cd < 1) {
168 cd++;
169 }
170 final long now = System.currentTimeMillis();
171 impl.setCoolDown(TimeValue.ofMilliseconds(cd));
172 clock.setCurrentTime(now);
173 impl.probe(route);
174 final int max0 = connPerRoute.getMaxPerRoute(route);
175 clock.setCurrentTime(now);
176 impl.probe(route);
177 assertEquals(max0, connPerRoute.getMaxPerRoute(route));
178 clock.setCurrentTime(now + cd + 1);
179 impl.probe(route);
180 assertTrue(max0 < connPerRoute.getMaxPerRoute(route));
181 }
182 }