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