View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.client5.http;
29  
30  import java.net.InetAddress;
31  import java.util.HashSet;
32  import java.util.Set;
33  
34  import org.apache.hc.client5.http.RouteInfo.LayerType;
35  import org.apache.hc.client5.http.RouteInfo.TunnelType;
36  import org.apache.hc.core5.http.HttpHost;
37  import org.apache.hc.core5.net.URIAuthority;
38  import org.junit.jupiter.api.Assertions;
39  import org.junit.jupiter.api.Test;
40  
41  /**
42   * Tests for {@link HttpRoute}.
43   */
44  public class TestHttpRoute {
45  
46      // a selection of constants for generating routes
47      public final static
48          HttpHost TARGET1 = new HttpHost("target1.test.invalid", 80);
49      public final static
50          HttpHost TARGET2 = new HttpHost("target2.test.invalid", 8080);
51      // It is not necessary to have extra targets for https.
52      // The 'layered' and 'secure' flags are specified explicitly
53      // for routes, they will not be determined from the scheme.
54  
55      public final static
56          HttpHost PROXY1 = new HttpHost("proxy1.test.invalid");
57      public final static
58          HttpHost PROXY2 = new HttpHost("proxy2.test.invalid", 1080);
59      public final static
60          HttpHost PROXY3 = new HttpHost("proxy3.test.invalid", 88);
61  
62      public final static InetAddress LOCAL41;
63      public final static InetAddress LOCAL42;
64      public final static InetAddress LOCAL61;
65      public final static InetAddress LOCAL62;
66  
67      // need static initializer to deal with exceptions
68      static {
69          try {
70              LOCAL41 = InetAddress.getByAddress(new byte[]{ 127, 0, 0, 1 });
71              LOCAL42 = InetAddress.getByAddress(new byte[]{ 127, 0, 0, 2 });
72  
73              LOCAL61 = InetAddress.getByAddress(new byte[]{
74                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
75              });
76              LOCAL62 = InetAddress.getByAddress(new byte[]{
77                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2
78              });
79  
80          } catch (final Exception x) {
81              throw new ExceptionInInitializerError(x);
82          }
83      }
84  
85      @Test
86      public void testCstrFullRoute() {
87          // create a route with all arguments and check the details
88          final HttpHost[] chain3 = { PROXY1, PROXY2, PROXY3 };
89  
90          final HttpRoute route = new HttpRoute(TARGET1, LOCAL41, chain3, false,
91                                          TunnelType.PLAIN, LayerType.PLAIN);
92          Assertions.assertEquals(TARGET1, route.getTargetHost(), "wrong target");
93          Assertions.assertEquals(LOCAL41, route.getLocalAddress(), "wrong local address");
94          Assertions.assertEquals(PROXY1, route.getProxyHost(), "wrong proxy host");
95          Assertions.assertEquals(4, route.getHopCount(), "wrong hop count");
96          Assertions.assertEquals(PROXY1, route.getHopTarget(0), "wrong hop 0");
97          Assertions.assertEquals(PROXY2, route.getHopTarget(1), "wrong hop 1");
98          Assertions.assertEquals(PROXY3, route.getHopTarget(2), "wrong hop 2");
99          Assertions.assertEquals(TARGET1, route.getHopTarget(3), "wrong hop 3");
100         Assertions.assertFalse(route.isSecure(), "wrong flag: secured");
101         Assertions.assertFalse(route.isTunnelled(), "wrong flag: tunnelled");
102         Assertions.assertFalse(route.isLayered(), "wrong flag: layered");
103 
104         final String routestr = route.toString();
105         Assertions.assertTrue(routestr.contains(TARGET1.getHostName()), "missing target in toString");
106         Assertions.assertTrue(routestr.contains(LOCAL41.toString()), "missing local address in toString");
107         Assertions.assertTrue(routestr.contains(PROXY1.getHostName()), "missing proxy 1 in toString");
108         Assertions.assertTrue(routestr.contains(PROXY2.getHostName()), "missing proxy 2 in toString");
109         Assertions.assertTrue(routestr.contains(PROXY3.getHostName()), "missing proxy 3 in toString");
110     }
111 
112     @Test
113     public void testCstrFullFlags() {
114         // tests the flag parameters in the full-blown constructor
115 
116         final HttpHost[] chain3 = { PROXY1, PROXY2, PROXY3 };
117 
118         final HttpRoute routefff = new HttpRoute
119             (TARGET1, LOCAL41, chain3, false,
120              TunnelType.PLAIN, LayerType.PLAIN);
121         final HttpRoute routefft = new HttpRoute
122             (TARGET1, LOCAL41, chain3, false,
123              TunnelType.PLAIN, LayerType.LAYERED);
124         final HttpRoute routeftf = new HttpRoute
125             (TARGET1, LOCAL41, chain3, false,
126              TunnelType.TUNNELLED, LayerType.PLAIN);
127         final HttpRoute routeftt = new HttpRoute
128             (TARGET1, LOCAL41, chain3, false,
129              TunnelType.TUNNELLED, LayerType.LAYERED);
130         final HttpRoute routetff = new HttpRoute
131             (TARGET1, LOCAL41, chain3, true,
132              TunnelType.PLAIN, LayerType.PLAIN);
133         final HttpRoute routetft = new HttpRoute
134             (TARGET1, LOCAL41, chain3, true,
135              TunnelType.PLAIN, LayerType.LAYERED);
136         final HttpRoute routettf = new HttpRoute
137             (TARGET1, LOCAL41, chain3, true,
138              TunnelType.TUNNELLED, LayerType.PLAIN);
139         final HttpRoute routettt = new HttpRoute
140             (TARGET1, LOCAL41, chain3, true,
141              TunnelType.TUNNELLED, LayerType.LAYERED);
142 
143         Assertions.assertFalse(routefff.isSecure(), "routefff.secure");
144         Assertions.assertFalse(routefff.isTunnelled(), "routefff.tunnel");
145         Assertions.assertFalse(routefff.isLayered(), "routefff.layer");
146 
147         Assertions.assertFalse(routefft.isSecure(), "routefft.secure");
148         Assertions.assertFalse(routefft.isTunnelled(), "routefft.tunnel");
149         Assertions.assertTrue (routefft.isLayered(), "routefft.layer");
150 
151         Assertions.assertFalse(routeftf.isSecure(), "routeftf.secure");
152         Assertions.assertTrue (routeftf.isTunnelled(), "routeftf.tunnel");
153         Assertions.assertFalse(routeftf.isLayered(), "routeftf.layer");
154 
155         Assertions.assertFalse(routeftt.isSecure(), "routeftt.secure");
156         Assertions.assertTrue (routeftt.isTunnelled(), "routeftt.tunnel");
157         Assertions.assertTrue (routeftt.isLayered(), "routeftt.layer");
158 
159         Assertions.assertTrue (routetff.isSecure(), "routetff.secure");
160         Assertions.assertFalse(routetff.isTunnelled(), "routetff.tunnel");
161         Assertions.assertFalse(routetff.isLayered(), "routetff.layer");
162 
163         Assertions.assertTrue (routetft.isSecure(), "routetft.secure");
164         Assertions.assertFalse(routetft.isTunnelled(), "routetft.tunnel");
165         Assertions.assertTrue (routetft.isLayered(), "routetft.layer");
166 
167         Assertions.assertTrue (routettf.isSecure(), "routettf.secure");
168         Assertions.assertTrue (routettf.isTunnelled(), "routettf.tunnel");
169         Assertions.assertFalse(routettf.isLayered(), "routettf.layer");
170 
171         Assertions.assertTrue (routettt.isSecure(), "routettt.secure");
172         Assertions.assertTrue (routettt.isTunnelled(), "routettt.tunnel");
173         Assertions.assertTrue (routettt.isLayered(), "routettt.layer");
174     }
175 
176     @Test
177     public void testInvalidArguments() {
178         final HttpHost[] chain1 = { PROXY1 };
179 
180         // for reference: this one should succeed
181         final HttpRoute route = new HttpRoute(TARGET1, null, chain1, false,
182                                         TunnelType.TUNNELLED, LayerType.PLAIN);
183         Assertions.assertNotNull(route);
184 
185         Assertions.assertThrows(NullPointerException.class, () ->
186                 new HttpRoute(null, null, chain1, false,TunnelType.TUNNELLED, LayerType.PLAIN));
187         Assertions.assertThrows(IllegalArgumentException.class, () ->
188                 new HttpRoute(TARGET1, null, (HttpHost[]) null, false, TunnelType.TUNNELLED, LayerType.PLAIN));
189     }
190 
191     @Test
192     public void testNullEnums() {
193 
194         // tests the default values for the enum parameters
195         // also covers the accessors for the enum attributes
196 
197         final HttpRoute route = new HttpRoute(TARGET1, null, PROXY1, false,
198                                         null, null); // here are defaults
199 
200         Assertions.assertFalse(route.isTunnelled(), "default tunnelling");
201         Assertions.assertEquals(TunnelType.PLAIN, route.getTunnelType(), "untunnelled");
202 
203         Assertions.assertFalse(route.isLayered(), "default layering");
204         Assertions.assertEquals(LayerType.PLAIN, route.getLayerType(), "unlayered");
205     }
206 
207     @Test
208     public void testEqualsHashcodeClone() throws CloneNotSupportedException {
209         final HttpHost[] chain0 = { };
210         final HttpHost[] chain1 = { PROXY1 };
211         final HttpHost[] chain3 = { PROXY1, PROXY2, PROXY3 };
212         final HttpHost[] chain4 = { PROXY1, PROXY3, PROXY2 };
213 
214         // create some identical routes
215         final HttpRoute route1a = new HttpRoute(TARGET1, LOCAL41, chain3, false,
216                                           TunnelType.PLAIN, LayerType.PLAIN);
217         final HttpRoute route1b = new HttpRoute(TARGET1, LOCAL41, chain3, false,
218                                           TunnelType.PLAIN, LayerType.PLAIN);
219         final HttpRoute route1c = (HttpRoute) route1a.clone();
220 
221         Assertions.assertEquals(route1a, route1a, "1a 1a");
222         Assertions.assertEquals(route1a, route1b, "1a 1b");
223         Assertions.assertEquals(route1a, route1c, "1a 1c");
224 
225         Assertions.assertEquals(route1a.hashCode(), route1a.hashCode(), "hashcode 1a");
226         Assertions.assertEquals(route1a.hashCode(), route1b.hashCode(), "hashcode 1b");
227         Assertions.assertEquals(route1a.hashCode(), route1c.hashCode(), "hashcode 1c");
228 
229         Assertions.assertEquals(route1a.toString(), route1b.toString(), "toString 1b");
230         Assertions.assertEquals(route1a.toString(), route1a.toString(), "toString 1a");
231         Assertions.assertEquals(route1a.toString(), route1c.toString(), "toString 1c");
232 
233         // now create some differing routes
234         final HttpRoute route2a = new HttpRoute(TARGET2, LOCAL41, chain3, false,
235                                           TunnelType.PLAIN, LayerType.PLAIN);
236         final HttpRoute route2b = new HttpRoute(TARGET1, LOCAL42, chain3, false,
237                                           TunnelType.PLAIN, LayerType.PLAIN);
238         final HttpRoute route2c = new HttpRoute(TARGET1, LOCAL61, chain3, false,
239                                           TunnelType.PLAIN, LayerType.PLAIN);
240         final HttpRoute route2d = new HttpRoute(TARGET1, null, chain3, false,
241                                           TunnelType.PLAIN, LayerType.PLAIN);
242         final HttpRoute route2e = new HttpRoute(TARGET1, LOCAL41, (HttpHost[]) null,
243                                           false,
244                                           TunnelType.PLAIN, LayerType.PLAIN);
245         final HttpRoute route2f = new HttpRoute(TARGET1, LOCAL41, chain0, false,
246                                           TunnelType.PLAIN, LayerType.PLAIN);
247         final HttpRoute route2g = new HttpRoute(TARGET1, LOCAL41, chain1, false,
248                                           TunnelType.PLAIN, LayerType.PLAIN);
249         final HttpRoute route2h = new HttpRoute(TARGET1, LOCAL41, chain4, false,
250                                           TunnelType.PLAIN, LayerType.PLAIN);
251         final HttpRoute route2i = new HttpRoute(TARGET1, LOCAL41, chain3, true,
252                                           TunnelType.PLAIN, LayerType.PLAIN);
253         final HttpRoute route2j = new HttpRoute(TARGET1, LOCAL41, chain3, false,
254                                         TunnelType.TUNNELLED, LayerType.PLAIN);
255         final HttpRoute route2k = new HttpRoute(TARGET1, LOCAL41, chain3, false,
256                                           TunnelType.PLAIN, LayerType.LAYERED);
257         final HttpRoute route2m = new HttpRoute(TARGET2,
258                 new URIAuthority(TARGET2.getHostName(), TARGET2.getPort()), LOCAL41, chain3, false,
259                 TunnelType.PLAIN, LayerType.PLAIN);
260 
261         // check a special case first: 2f should be the same as 2e
262         Assertions.assertEquals(route2e, route2f, "2e 2f");
263         Assertions.assertEquals(route2e.hashCode(), route2f.hashCode(), "hashcode 2e 2f");
264         Assertions.assertEquals(route2e.toString(), route2f.toString(), "toString 2e 2f");
265 
266         Assertions.assertNotEquals(route1a, route2a, "1a 2a");
267         Assertions.assertNotEquals(route1a, route2b, "1a 2b");
268         Assertions.assertNotEquals(route1a, route2c, "1a 2c");
269         Assertions.assertNotEquals(route1a, route2d, "1a 2d");
270         Assertions.assertNotEquals(route1a, route2e, "1a 2e");
271         Assertions.assertNotEquals(route1a, route2f, "1a 2f");
272         Assertions.assertNotEquals(route1a, route2g, "1a 2g");
273         Assertions.assertNotEquals(route1a, route2h, "1a 2h");
274         Assertions.assertNotEquals(route1a, route2i, "1a 2i");
275         Assertions.assertNotEquals(route1a, route2j, "1a 2j");
276         Assertions.assertNotEquals(route1a, route2k, "1a 2k");
277         Assertions.assertNotEquals(route1a, route2m, "1a 2k");
278 
279         // repeat the checks in the other direction
280         // there could be problems with detecting null attributes
281 
282         Assertions.assertNotEquals(route2b, route1a, "2b 1a");
283         Assertions.assertNotEquals(route2c, route1a, "2c 1a");
284         Assertions.assertNotEquals(route2d, route1a, "2d 1a");
285         Assertions.assertNotEquals(route2e, route1a, "2e 1a");
286         Assertions.assertNotEquals(route2a, route1a, "2a 1a");
287         Assertions.assertNotEquals(route2f, route1a, "2f 1a");
288         Assertions.assertNotEquals(route2g, route1a, "2g 1a");
289         Assertions.assertNotEquals(route2h, route1a, "2h 1a");
290         Assertions.assertNotEquals(route2i, route1a, "2i 1a");
291         Assertions.assertNotEquals(route2j, route1a, "2j 1a");
292         Assertions.assertNotEquals(route2k, route1a, "2k 1a");
293         Assertions.assertNotEquals(route2m, route1a, "2k 1a");
294 
295         // don't check hashCode, it's not guaranteed to be different
296 
297         Assertions.assertNotEquals(route1a.toString(), route2a.toString(), "toString 1a 2a");
298         Assertions.assertNotEquals(route1a.toString(), route2b.toString(), "toString 1a 2b");
299         Assertions.assertNotEquals(route1a.toString(), route2c.toString(), "toString 1a 2c");
300         Assertions.assertNotEquals(route1a.toString(), route2d.toString(), "toString 1a 2d");
301         Assertions.assertNotEquals(route1a.toString(), route2e.toString(), "toString 1a 2e");
302         Assertions.assertNotEquals(route1a.toString(), route2f.toString(), "toString 1a 2f");
303         Assertions.assertNotEquals(route1a.toString(), route2g.toString(), "toString 1a 2g");
304         Assertions.assertNotEquals(route1a.toString(), route2h.toString(), "toString 1a 2h");
305         Assertions.assertNotEquals(route1a.toString(), route2i.toString(), "toString 1a 2i");
306         Assertions.assertNotEquals(route1a.toString(), route2j.toString(), "toString 1a 2j");
307         Assertions.assertNotEquals(route1a.toString(), route2k.toString(), "toString 1a 2k");
308         Assertions.assertNotEquals(route1a.toString(), route2m.toString(), "toString 1a 2k");
309 
310         // now check that all of the routes are different from eachother
311         // except for those that aren't :-)
312         final Set<HttpRoute> routes = new HashSet<>();
313         routes.add(route1a);
314         routes.add(route2a);
315         routes.add(route2b);
316         routes.add(route2c);
317         routes.add(route2d);
318         routes.add(route2e);
319         //routes.add(route2f); // 2f is the same as 2e
320         routes.add(route2g);
321         routes.add(route2h);
322         routes.add(route2i);
323         routes.add(route2j);
324         routes.add(route2k);
325         routes.add(route2m);
326 
327         // and a run of cloning over the set
328         for (final HttpRoute origin : routes) {
329             final HttpRoute cloned = (HttpRoute) origin.clone();
330             Assertions.assertEquals(origin, cloned, "clone of " + origin);
331             Assertions.assertTrue(routes.contains(cloned), "clone of " + origin);
332         }
333 
334         // finally, compare with nonsense
335         Assertions.assertNotEquals(null, route1a, "route equals null");
336         Assertions.assertNotEquals("route1a", route1a, "route equals string");
337     }
338 
339     @Test
340     public void testHopping() {
341         // test getHopCount() and getHopTarget() with different proxy chains
342         final HttpHost[] proxies = null;
343         final HttpRoute  route   = new HttpRoute(TARGET1, null, proxies, true,
344                                            TunnelType.PLAIN, LayerType.PLAIN);
345         Assertions.assertEquals(1, route.getHopCount(), "A: hop count");
346         Assertions.assertEquals(TARGET1, route.getHopTarget(0), "A: hop 0");
347         Assertions.assertThrows(IllegalArgumentException.class, () -> route.getHopTarget(1));
348         Assertions.assertThrows(IllegalArgumentException.class, () ->  route.getHopTarget(-1));
349 
350         final HttpHost[] proxies2 = new HttpHost[]{ PROXY3 };
351         final HttpRoute route2   = new HttpRoute(TARGET1, LOCAL62, proxies2, false,
352                                 TunnelType.TUNNELLED, LayerType.PLAIN);
353         Assertions.assertEquals(2, route2.getHopCount(), "B: hop count");
354         Assertions.assertEquals(PROXY3, route2.getHopTarget(0), "B: hop 0");
355         Assertions.assertEquals(TARGET1, route2.getHopTarget(1), "B: hop 1");
356         Assertions.assertThrows(IllegalArgumentException.class, () -> route2.getHopTarget(2));
357         Assertions.assertThrows(IllegalArgumentException.class, () -> route2.getHopTarget(-2));
358 
359         final HttpHost[] proxies3 = new HttpHost[]{ PROXY3, PROXY1, PROXY2 };
360         final HttpRoute route3   = new HttpRoute(TARGET1, LOCAL42, proxies3, false,
361                                 TunnelType.PLAIN, LayerType.LAYERED);
362         Assertions.assertEquals(route3.getHopCount(), 4, "C: hop count");
363         Assertions.assertEquals(PROXY3 , route3.getHopTarget(0), "C: hop 0");
364         Assertions.assertEquals(PROXY1 , route3.getHopTarget(1), "C: hop 1");
365         Assertions.assertEquals(PROXY2 , route3.getHopTarget(2), "C: hop 2");
366         Assertions.assertEquals(TARGET1, route3.getHopTarget(3), "C: hop 3");
367         Assertions.assertThrows(IllegalArgumentException.class, () -> route3.getHopTarget(4));
368         Assertions.assertThrows(IllegalArgumentException.class, () -> route3.getHopTarget(Integer.MIN_VALUE));
369     }
370 
371     @Test
372     public void testCstr1() {
373         final HttpRoute route = new HttpRoute(TARGET2);
374         final HttpRoute should = new HttpRoute
375             (TARGET2, null, (HttpHost[]) null, false,
376              TunnelType.PLAIN, LayerType.PLAIN);
377         Assertions.assertEquals(route, should, "bad convenience route");
378     }
379 
380     @Test
381     public void testCstr3() {
382         // test convenience constructor with 3 arguments
383         HttpRoute route = new HttpRoute(TARGET2, LOCAL61, false);
384         HttpRoute should = new HttpRoute
385             (TARGET2, LOCAL61, (HttpHost[]) null, false,
386              TunnelType.PLAIN, LayerType.PLAIN);
387         Assertions.assertEquals(route, should, "bad convenience route 3/insecure");
388 
389         route = new HttpRoute(TARGET2, null, true);
390         should = new HttpRoute(TARGET2, null, (HttpHost[]) null, true,
391                                TunnelType.PLAIN, LayerType.PLAIN);
392         Assertions.assertEquals(route, should, "bad convenience route 3/secure");
393     }
394 
395     @SuppressWarnings("unused")
396     @Test
397     public void testCstr4() {
398         // test convenience constructor with 4 arguments
399         HttpRoute route = new HttpRoute(TARGET2, null, PROXY2, false);
400         HttpRoute should = new HttpRoute
401             (TARGET2, null, new HttpHost[]{ PROXY2 }, false,
402              TunnelType.PLAIN, LayerType.PLAIN);
403         Assertions.assertEquals(route, should, "bad convenience route 4/insecure");
404 
405         route = new HttpRoute(TARGET2, LOCAL42, PROXY1, true);
406         should = new HttpRoute
407             (TARGET2, LOCAL42, new HttpHost[]{ PROXY1 }, true,
408              TunnelType.TUNNELLED, LayerType.LAYERED);
409         Assertions.assertEquals(route, should, "bad convenience route 4/secure");
410 
411         // this constructor REQUIRES a proxy to be specified
412         Assertions.assertThrows(NullPointerException.class, () ->
413                 new HttpRoute(TARGET1, LOCAL61, null, false));
414     }
415 
416     @Test
417     public void testCstr6() {
418         // test convenience constructor with 6 arguments
419         HttpRoute route = new HttpRoute
420             (TARGET2, null, PROXY2, true,
421              TunnelType.TUNNELLED, LayerType.PLAIN);
422         HttpRoute should = new HttpRoute
423             (TARGET2, null, new HttpHost[]{ PROXY2 }, true,
424              TunnelType.TUNNELLED, LayerType.PLAIN);
425         Assertions.assertEquals(route, should, "bad convenience route 6/proxied");
426 
427         route = new HttpRoute
428             (TARGET2, null, (HttpHost) null, true,
429              TunnelType.PLAIN, LayerType.LAYERED);
430         should = new HttpRoute
431             (TARGET2, null, (HttpHost[]) null, true,
432              TunnelType.PLAIN, LayerType.LAYERED);
433         Assertions.assertEquals(route, should, "bad convenience route 6/direct");
434 
435         // handling of null vs. empty chain is checked in the equals tests
436     }
437 
438     @Test
439     public void testImmutable() throws CloneNotSupportedException {
440 
441         final HttpHost[] proxies = new HttpHost[]{ PROXY1, PROXY2, PROXY3 };
442         final HttpRoute route1 = new HttpRoute(TARGET1, null, proxies, false,
443                                          TunnelType.PLAIN, LayerType.PLAIN);
444         final HttpRoute route2 = (HttpRoute) route1.clone();
445         final HttpRoute route3 = new HttpRoute(TARGET1, null,
446                                          proxies.clone(), false,
447                                          TunnelType.PLAIN, LayerType.PLAIN);
448 
449         // modify the array that was passed to the constructor of route1
450         proxies[1] = PROXY3;
451         proxies[2] = PROXY2;
452 
453         Assertions.assertEquals(route2, route1, "route differs from clone");
454         Assertions.assertEquals(route3, route1, "route was modified");
455     }
456 
457 }