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 org.apache.hc.client5.http.HttpRoute;
30 import org.apache.hc.core5.http.HttpHost;
31 import org.apache.hc.core5.util.TimeValue;
32 import org.junit.jupiter.api.BeforeEach;
33 import org.junit.jupiter.api.Test;
34
35
36 import static org.junit.jupiter.api.Assertions.assertEquals;
37 import static org.junit.jupiter.api.Assertions.assertTrue;
38
39 public class TestExponentialBackoffManager {
40
41 private ExponentialBackoffManager impl;
42 private MockConnPoolControl connPerRoute;
43 private HttpRoute route;
44 private static final long DEFAULT_COOL_DOWN_MS = 5000;
45
46 @BeforeEach
47 public void setUp() {
48 connPerRoute = new MockConnPoolControl();
49 route = new HttpRoute(new HttpHost("localhost", 80));
50 impl = new ExponentialBackoffManager(connPerRoute);
51 impl.setPerHostConnectionCap(10);
52 impl.setCoolDown(TimeValue.ofMilliseconds(DEFAULT_COOL_DOWN_MS));
53 impl.setBackoffFactor(1.75);
54 }
55
56 @Test
57 public void exponentialBackoffApplied() {
58 connPerRoute.setMaxPerRoute(route, 4);
59 impl.setBackoffFactor(2);
60 impl.backOff(route);
61 assertEquals(1, connPerRoute.getMaxPerRoute(route));
62 }
63
64 @Test
65 public void exponentialGrowthRateIsConfigurable() throws InterruptedException {
66 final int customCoolDownMs = 500;
67 connPerRoute.setMaxPerRoute(route, 4);
68 impl.setBackoffFactor(0.5);
69 impl.setCoolDown(TimeValue.ofMilliseconds(customCoolDownMs));
70 impl.backOff(route);
71 assertEquals(2, connPerRoute.getMaxPerRoute(route));
72 Thread.sleep(customCoolDownMs + 100);
73 impl.backOff(route);
74 assertEquals(1, connPerRoute.getMaxPerRoute(route));
75 }
76
77 @Test
78 public void doesNotIncreaseBeyondPerHostMaxOnProbe() {
79 connPerRoute.setDefaultMaxPerRoute(5);
80 connPerRoute.setMaxPerRoute(route, 5);
81 impl.setPerHostConnectionCap(5);
82 impl.probe(route);
83 assertEquals(5, connPerRoute.getMaxPerRoute(route));
84 }
85
86 @Test
87 public void backoffDoesNotAdjustDuringCoolDownPeriod() throws InterruptedException {
88 connPerRoute.setMaxPerRoute(route, 4);
89 impl.backOff(route);
90 final long max = connPerRoute.getMaxPerRoute(route);
91 Thread.sleep(1);
92 impl.backOff(route);
93 assertEquals(max, connPerRoute.getMaxPerRoute(route));
94 }
95
96 @Test
97 public void backoffStillAdjustsAfterCoolDownPeriod() throws InterruptedException {
98 connPerRoute.setMaxPerRoute(route, 8);
99 impl.backOff(route);
100 final long max = connPerRoute.getMaxPerRoute(route);
101 Thread.sleep(DEFAULT_COOL_DOWN_MS + 1);
102 impl.backOff(route);
103 assertTrue(max == 1 || max > connPerRoute.getMaxPerRoute(route));
104 }
105
106 @Test
107 public void probeDoesNotAdjustDuringCooldownPeriod() throws InterruptedException {
108 connPerRoute.setMaxPerRoute(route, 4);
109 impl.probe(route);
110 final long max = connPerRoute.getMaxPerRoute(route);
111 Thread.sleep(1);
112 impl.probe(route);
113 assertEquals(max, connPerRoute.getMaxPerRoute(route));
114 }
115
116 @Test
117 public void probeStillAdjustsAfterCoolDownPeriod() throws InterruptedException {
118 connPerRoute.setMaxPerRoute(route, 8);
119 impl.probe(route);
120 final long max = connPerRoute.getMaxPerRoute(route);
121 Thread.sleep(DEFAULT_COOL_DOWN_MS + 1);
122 impl.probe(route);
123 assertTrue(max < connPerRoute.getMaxPerRoute(route));
124 }
125
126 @Test
127 public void willBackoffImmediatelyEvenAfterAProbe() {
128 connPerRoute.setMaxPerRoute(route, 8);
129 final long now = System.currentTimeMillis();
130 impl.probe(route);
131 final long max = connPerRoute.getMaxPerRoute(route);
132 impl.backOff(route);
133 assertTrue(connPerRoute.getMaxPerRoute(route) < max);
134 }
135
136 @Test
137 public void coolDownPeriodIsConfigurable() throws InterruptedException {
138 final long cd = 500;
139 impl.setCoolDown(TimeValue.ofMilliseconds(cd));
140
141
142 Thread.sleep(100);
143
144
145 impl.probe(route);
146 final int max0 = connPerRoute.getMaxPerRoute(route);
147 Thread.sleep(cd / 2);
148 impl.probe(route);
149 assertEquals(max0, connPerRoute.getMaxPerRoute(route));
150
151
152 Thread.sleep(cd / 2 + 1);
153 impl.probe(route);
154 assertTrue(max0 < connPerRoute.getMaxPerRoute(route));
155 }
156
157 }