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.http.conn.routing;
29  
30  import java.net.InetAddress;
31  import java.util.HashSet;
32  import java.util.Iterator;
33  import java.util.Set;
34  
35  import org.apache.http.HttpHost;
36  import org.apache.http.conn.routing.RouteInfo.LayerType;
37  import org.apache.http.conn.routing.RouteInfo.TunnelType;
38  import org.junit.Assert;
39  import org.junit.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");
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          Assert.assertEquals("wrong target",
93                       TARGET1, route.getTargetHost());
94          Assert.assertEquals("wrong local address",
95                       LOCAL41, route.getLocalAddress());
96          Assert.assertEquals("wrong proxy host",
97                       PROXY1, route.getProxyHost());
98          Assert.assertEquals("wrong hop count",
99                       4, route.getHopCount());
100         Assert.assertEquals("wrong hop 0",
101                      PROXY1, route.getHopTarget(0));
102         Assert.assertEquals("wrong hop 1",
103                      PROXY2, route.getHopTarget(1));
104         Assert.assertEquals("wrong hop 2",
105                      PROXY3, route.getHopTarget(2));
106         Assert.assertEquals("wrong hop 3",
107                      TARGET1, route.getHopTarget(3));
108         Assert.assertFalse("wrong flag: secured", route.isSecure());
109         Assert.assertFalse("wrong flag: tunnelled", route.isTunnelled());
110         Assert.assertFalse("wrong flag: layered", route.isLayered());
111 
112         final String routestr = route.toString();
113         Assert.assertTrue("missing target in toString",
114                 routestr.contains(TARGET1.getHostName()));
115         Assert.assertTrue("missing local address in toString",
116                 routestr.contains(LOCAL41.toString()));
117         Assert.assertTrue("missing proxy 1 in toString",
118                 routestr.contains(PROXY1.getHostName()));
119         Assert.assertTrue("missing proxy 2 in toString",
120                 routestr.contains(PROXY2.getHostName()));
121         Assert.assertTrue("missing proxy 3 in toString",
122                 routestr.contains(PROXY3.getHostName()));
123     }
124 
125     @Test
126     public void testCstrFullFlags() {
127         // tests the flag parameters in the full-blown constructor
128 
129         final HttpHost[] chain3 = { PROXY1, PROXY2, PROXY3 };
130 
131         final HttpRoute routefff = new HttpRoute
132             (TARGET1, LOCAL41, chain3, false,
133              TunnelType.PLAIN, LayerType.PLAIN);
134         final HttpRoute routefft = new HttpRoute
135             (TARGET1, LOCAL41, chain3, false,
136              TunnelType.PLAIN, LayerType.LAYERED);
137         final HttpRoute routeftf = new HttpRoute
138             (TARGET1, LOCAL41, chain3, false,
139              TunnelType.TUNNELLED, LayerType.PLAIN);
140         final HttpRoute routeftt = new HttpRoute
141             (TARGET1, LOCAL41, chain3, false,
142              TunnelType.TUNNELLED, LayerType.LAYERED);
143         final HttpRoute routetff = new HttpRoute
144             (TARGET1, LOCAL41, chain3, true,
145              TunnelType.PLAIN, LayerType.PLAIN);
146         final HttpRoute routetft = new HttpRoute
147             (TARGET1, LOCAL41, chain3, true,
148              TunnelType.PLAIN, LayerType.LAYERED);
149         final HttpRoute routettf = new HttpRoute
150             (TARGET1, LOCAL41, chain3, true,
151              TunnelType.TUNNELLED, LayerType.PLAIN);
152         final HttpRoute routettt = new HttpRoute
153             (TARGET1, LOCAL41, chain3, true,
154              TunnelType.TUNNELLED, LayerType.LAYERED);
155 
156         Assert.assertFalse("routefff.secure", routefff.isSecure());
157         Assert.assertFalse("routefff.tunnel", routefff.isTunnelled());
158         Assert.assertFalse("routefff.layer" , routefff.isLayered());
159 
160         Assert.assertFalse("routefft.secure", routefft.isSecure());
161         Assert.assertFalse("routefft.tunnel", routefft.isTunnelled());
162         Assert.assertTrue ("routefft.layer" , routefft.isLayered());
163 
164         Assert.assertFalse("routeftf.secure", routeftf.isSecure());
165         Assert.assertTrue ("routeftf.tunnel", routeftf.isTunnelled());
166         Assert.assertFalse("routeftf.layer" , routeftf.isLayered());
167 
168         Assert.assertFalse("routeftt.secure", routeftt.isSecure());
169         Assert.assertTrue ("routeftt.tunnel", routeftt.isTunnelled());
170         Assert.assertTrue ("routeftt.layer" , routeftt.isLayered());
171 
172         Assert.assertTrue ("routetff.secure", routetff.isSecure());
173         Assert.assertFalse("routetff.tunnel", routetff.isTunnelled());
174         Assert.assertFalse("routetff.layer" , routetff.isLayered());
175 
176         Assert.assertTrue ("routetft.secure", routetft.isSecure());
177         Assert.assertFalse("routetft.tunnel", routetft.isTunnelled());
178         Assert.assertTrue ("routetft.layer" , routetft.isLayered());
179 
180         Assert.assertTrue ("routettf.secure", routettf.isSecure());
181         Assert.assertTrue ("routettf.tunnel", routettf.isTunnelled());
182         Assert.assertFalse("routettf.layer" , routettf.isLayered());
183 
184         Assert.assertTrue ("routettt.secure", routettt.isSecure());
185         Assert.assertTrue ("routettt.tunnel", routettt.isTunnelled());
186         Assert.assertTrue ("routettt.layer" , routettt.isLayered());
187 
188 
189         final Set<HttpRoute> routes = new HashSet<HttpRoute>();
190         routes.add(routefff);
191         routes.add(routefft);
192         routes.add(routeftf);
193         routes.add(routeftt);
194         routes.add(routetff);
195         routes.add(routetft);
196         routes.add(routettf);
197         routes.add(routettt);
198         Assert.assertEquals("some flagged routes are equal", 8, routes.size());
199 
200         // we can't test hashCode in general due to its dependency
201         // on InetAddress and HttpHost, but we can check for the flags
202         final Set<Integer> routecodes = new HashSet<Integer>();
203         routecodes.add(Integer.valueOf(routefff.hashCode()));
204         routecodes.add(Integer.valueOf(routefft.hashCode()));
205         routecodes.add(Integer.valueOf(routeftf.hashCode()));
206         routecodes.add(Integer.valueOf(routeftt.hashCode()));
207         routecodes.add(Integer.valueOf(routetff.hashCode()));
208         routecodes.add(Integer.valueOf(routetft.hashCode()));
209         routecodes.add(Integer.valueOf(routettf.hashCode()));
210         routecodes.add(Integer.valueOf(routettt.hashCode()));
211         Assert.assertEquals("some flagged routes have same hashCode",
212                      8, routecodes.size());
213 
214         final Set<String> routestrings = new HashSet<String>();
215         routestrings.add(routefff.toString());
216         routestrings.add(routefft.toString());
217         routestrings.add(routeftf.toString());
218         routestrings.add(routeftt.toString());
219         routestrings.add(routetff.toString());
220         routestrings.add(routetft.toString());
221         routestrings.add(routettf.toString());
222         routestrings.add(routettt.toString());
223         Assert.assertEquals("some flagged route.toString() are equal",
224                      8, routestrings.size());
225     }
226 
227     @SuppressWarnings("unused")
228     @Test
229     public void testInvalidArguments() {
230         final HttpHost[] chain1 = { PROXY1 };
231 
232         // for reference: this one should succeed
233         final HttpRoute route = new HttpRoute(TARGET1, null, chain1, false,
234                                         TunnelType.TUNNELLED, LayerType.PLAIN);
235         Assert.assertNotNull(route);
236 
237         try {
238             new HttpRoute(null, null, chain1, false,
239                                   TunnelType.TUNNELLED, LayerType.PLAIN);
240             Assert.fail("missing target not detected");
241         } catch (final IllegalArgumentException iax) {
242             // expected
243         }
244 
245         try {
246             new HttpRoute(TARGET1, null, (HttpHost[]) null, false,
247                                   TunnelType.TUNNELLED, LayerType.PLAIN);
248             Assert.fail("missing proxy for tunnel not detected");
249         } catch (final IllegalArgumentException iax) {
250             // expected
251         }
252     }
253 
254     @Test
255     public void testNullEnums() {
256 
257         // tests the default values for the enum parameters
258         // also covers the accessors for the enum attributes
259 
260         final HttpRoute route = new HttpRoute(TARGET1, null, PROXY1, false,
261                                         null, null); // here are defaults
262 
263         Assert.assertFalse("default tunnelling", route.isTunnelled());
264         Assert.assertEquals("untunnelled", TunnelType.PLAIN, route.getTunnelType());
265 
266         Assert.assertFalse("default layering", route.isLayered());
267         Assert.assertEquals("unlayered", LayerType.PLAIN, route.getLayerType());
268     }
269 
270     @Test
271     public void testEqualsHashcodeClone() throws CloneNotSupportedException {
272         final HttpHost[] chain0 = { };
273         final HttpHost[] chain1 = { PROXY1 };
274         final HttpHost[] chain3 = { PROXY1, PROXY2, PROXY3 };
275         final HttpHost[] chain4 = { PROXY1, PROXY3, PROXY2 };
276 
277         // create some identical routes
278         final HttpRoute route1a = new HttpRoute(TARGET1, LOCAL41, chain3, false,
279                                           TunnelType.PLAIN, LayerType.PLAIN);
280         final HttpRoute route1b = new HttpRoute(TARGET1, LOCAL41, chain3, false,
281                                           TunnelType.PLAIN, LayerType.PLAIN);
282         final HttpRoute route1c = (HttpRoute) route1a.clone();
283 
284         Assert.assertEquals("1a 1a", route1a, route1a);
285         Assert.assertEquals("1a 1b", route1a, route1b);
286         Assert.assertEquals("1a 1c", route1a, route1c);
287 
288         Assert.assertEquals("hashcode 1a", route1a.hashCode(), route1a.hashCode());
289         Assert.assertEquals("hashcode 1b", route1a.hashCode(), route1b.hashCode());
290         Assert.assertEquals("hashcode 1c", route1a.hashCode(), route1c.hashCode());
291 
292         Assert.assertEquals("toString 1a", route1a.toString(), route1a.toString());
293         Assert.assertEquals("toString 1b", route1a.toString(), route1b.toString());
294         Assert.assertEquals("toString 1c", route1a.toString(), route1c.toString());
295 
296         // now create some differing routes
297         final HttpRoute route2a = new HttpRoute(TARGET2, LOCAL41, chain3, false,
298                                           TunnelType.PLAIN, LayerType.PLAIN);
299         final HttpRoute route2b = new HttpRoute(TARGET1, LOCAL42, chain3, false,
300                                           TunnelType.PLAIN, LayerType.PLAIN);
301         final HttpRoute route2c = new HttpRoute(TARGET1, LOCAL61, chain3, false,
302                                           TunnelType.PLAIN, LayerType.PLAIN);
303         final HttpRoute route2d = new HttpRoute(TARGET1, null, chain3, false,
304                                           TunnelType.PLAIN, LayerType.PLAIN);
305         final HttpRoute route2e = new HttpRoute(TARGET1, LOCAL41, (HttpHost[]) null,
306                                           false,
307                                           TunnelType.PLAIN, LayerType.PLAIN);
308         final HttpRoute route2f = new HttpRoute(TARGET1, LOCAL41, chain0, false,
309                                           TunnelType.PLAIN, LayerType.PLAIN);
310         final HttpRoute route2g = new HttpRoute(TARGET1, LOCAL41, chain1, false,
311                                           TunnelType.PLAIN, LayerType.PLAIN);
312         final HttpRoute route2h = new HttpRoute(TARGET1, LOCAL41, chain4, false,
313                                           TunnelType.PLAIN, LayerType.PLAIN);
314         final HttpRoute route2i = new HttpRoute(TARGET1, LOCAL41, chain3, true,
315                                           TunnelType.PLAIN, LayerType.PLAIN);
316         final HttpRoute route2j = new HttpRoute(TARGET1, LOCAL41, chain3, false,
317                                         TunnelType.TUNNELLED, LayerType.PLAIN);
318         final HttpRoute route2k = new HttpRoute(TARGET1, LOCAL41, chain3, false,
319                                           TunnelType.PLAIN, LayerType.LAYERED);
320 
321         // check a special case first: 2f should be the same as 2e
322         Assert.assertEquals("2e 2f", route2e, route2f);
323         Assert.assertEquals("hashcode 2e 2f", route2e.hashCode(), route2f.hashCode());
324         Assert.assertEquals("toString 2e 2f", route2e.toString(), route2f.toString());
325 
326         Assert.assertFalse("1a 2a", route1a.equals(route2a));
327         Assert.assertFalse("1a 2b", route1a.equals(route2b));
328         Assert.assertFalse("1a 2c", route1a.equals(route2c));
329         Assert.assertFalse("1a 2d", route1a.equals(route2d));
330         Assert.assertFalse("1a 2e", route1a.equals(route2e));
331         Assert.assertFalse("1a 2f", route1a.equals(route2f));
332         Assert.assertFalse("1a 2g", route1a.equals(route2g));
333         Assert.assertFalse("1a 2h", route1a.equals(route2h));
334         Assert.assertFalse("1a 2i", route1a.equals(route2i));
335         Assert.assertFalse("1a 2j", route1a.equals(route2j));
336         Assert.assertFalse("1a 2k", route1a.equals(route2k));
337 
338         // repeat the checks in the other direction
339         // there could be problems with detecting null attributes
340 
341         Assert.assertFalse("2a 1a", route2a.equals(route1a));
342         Assert.assertFalse("2b 1a", route2b.equals(route1a));
343         Assert.assertFalse("2c 1a", route2c.equals(route1a));
344         Assert.assertFalse("2d 1a", route2d.equals(route1a));
345         Assert.assertFalse("2e 1a", route2e.equals(route1a));
346         Assert.assertFalse("2f 1a", route2f.equals(route1a));
347         Assert.assertFalse("2g 1a", route2g.equals(route1a));
348         Assert.assertFalse("2h 1a", route2h.equals(route1a));
349         Assert.assertFalse("2i 1a", route2i.equals(route1a));
350         Assert.assertFalse("2j 1a", route2j.equals(route1a));
351         Assert.assertFalse("2k 1a", route2k.equals(route1a));
352 
353         // don't check hashCode, it's not guaranteed to be different
354 
355         Assert.assertFalse("toString 1a 2a",
356                     route1a.toString().equals(route2a.toString()));
357         Assert.assertFalse("toString 1a 2b",
358                     route1a.toString().equals(route2b.toString()));
359         Assert.assertFalse("toString 1a 2c",
360                     route1a.toString().equals(route2c.toString()));
361         Assert.assertFalse("toString 1a 2d",
362                     route1a.toString().equals(route2d.toString()));
363         Assert.assertFalse("toString 1a 2e",
364                     route1a.toString().equals(route2e.toString()));
365         Assert.assertFalse("toString 1a 2f",
366                     route1a.toString().equals(route2f.toString()));
367         Assert.assertFalse("toString 1a 2g",
368                     route1a.toString().equals(route2g.toString()));
369         Assert.assertFalse("toString 1a 2h",
370                     route1a.toString().equals(route2h.toString()));
371         Assert.assertFalse("toString 1a 2i",
372                     route1a.toString().equals(route2i.toString()));
373         Assert.assertFalse("toString 1a 2j",
374                     route1a.toString().equals(route2j.toString()));
375         Assert.assertFalse("toString 1a 2k",
376                     route1a.toString().equals(route2k.toString()));
377 
378         // now check that all of the routes are different from eachother
379         // except for those that aren't :-)
380         final Set<HttpRoute> routes = new HashSet<HttpRoute>();
381         routes.add(route1a);
382         routes.add(route2a);
383         routes.add(route2b);
384         routes.add(route2c);
385         routes.add(route2d);
386         routes.add(route2e);
387         //routes.add(route2f); // 2f is the same as 2e
388         routes.add(route2g);
389         routes.add(route2h);
390         routes.add(route2i);
391         routes.add(route2j);
392         routes.add(route2k);
393         Assert.assertEquals("some routes are equal", 11, routes.size());
394 
395         // and a run of cloning over the set
396         final Iterator<HttpRoute> iter = routes.iterator();
397         while (iter.hasNext()) {
398             final HttpRoute origin = iter.next();
399             final HttpRoute cloned = (HttpRoute) origin.clone();
400             Assert.assertEquals("clone of " + origin, origin, cloned);
401             Assert.assertTrue("clone of " + origin, routes.contains(cloned));
402         }
403 
404         // and don't forget toString
405         final Set<String> routestrings = new HashSet<String>();
406         routestrings.add(route1a.toString());
407         routestrings.add(route2a.toString());
408         routestrings.add(route2b.toString());
409         routestrings.add(route2c.toString());
410         routestrings.add(route2d.toString());
411         routestrings.add(route2e.toString());
412         //routestrings.add(route2f.toString()); // 2f is the same as 2e
413         routestrings.add(route2g.toString());
414         routestrings.add(route2h.toString());
415         routestrings.add(route2i.toString());
416         routestrings.add(route2j.toString());
417         routestrings.add(route2k.toString());
418         Assert.assertEquals("some route.toString() are equal",
419                      11, routestrings.size());
420 
421         // finally, compare with nonsense
422         Assert.assertFalse("route equals null", route1a.equals(null));
423         Assert.assertFalse("route equals string", route1a.equals("route1a"));
424     }
425 
426     @Test
427     public void testHopping() {
428         // test getHopCount() and getHopTarget() with different proxy chains
429         HttpHost[] proxies = null;
430         HttpRoute  route   = new HttpRoute(TARGET1, null, proxies, true,
431                                            TunnelType.PLAIN, LayerType.PLAIN);
432         Assert.assertEquals("A: hop count", 1, route.getHopCount());
433         Assert.assertEquals("A: hop 0", TARGET1, route.getHopTarget(0));
434         try {
435             final HttpHost beyond = route.getHopTarget(1);
436             Assert.fail("A: hop 1 is " + beyond);
437         } catch (final IllegalArgumentException iax) {
438             // expected
439         }
440         try {
441             final HttpHost before = route.getHopTarget(-1);
442             Assert.fail("A: hop -1 is " + before);
443         } catch (final IllegalArgumentException iax) {
444             // expected
445         }
446 
447 
448         proxies = new HttpHost[]{ PROXY3 };
449         route   = new HttpRoute(TARGET1, LOCAL62, proxies, false,
450                                 TunnelType.TUNNELLED, LayerType.PLAIN);
451         Assert.assertEquals("B: hop count", 2, route.getHopCount());
452         Assert.assertEquals("B: hop 0", PROXY3, route.getHopTarget(0));
453         Assert.assertEquals("B: hop 1", TARGET1, route.getHopTarget(1));
454         try {
455             final HttpHost beyond = route.getHopTarget(2);
456             Assert.fail("B: hop 2 is " + beyond);
457         } catch (final IllegalArgumentException iax) {
458             // expected
459         }
460         try {
461             final HttpHost before = route.getHopTarget(-2);
462             Assert.fail("B: hop -2 is " + before);
463         } catch (final IllegalArgumentException iax) {
464             // expected
465         }
466 
467 
468         proxies = new HttpHost[]{ PROXY3, PROXY1, PROXY2 };
469         route   = new HttpRoute(TARGET1, LOCAL42, proxies, false,
470                                 TunnelType.PLAIN, LayerType.LAYERED);
471         Assert.assertEquals("C: hop count", 4, route.getHopCount());
472         Assert.assertEquals("C: hop 0", PROXY3 , route.getHopTarget(0));
473         Assert.assertEquals("C: hop 1", PROXY1 , route.getHopTarget(1));
474         Assert.assertEquals("C: hop 2", PROXY2 , route.getHopTarget(2));
475         Assert.assertEquals("C: hop 3", TARGET1, route.getHopTarget(3));
476         try {
477             final HttpHost beyond = route.getHopTarget(4);
478             Assert.fail("C: hop 4 is " + beyond);
479         } catch (final IllegalArgumentException iax) {
480             // expected
481         }
482         try {
483             final HttpHost before = route.getHopTarget(Integer.MIN_VALUE);
484             Assert.fail("C: hop -<min> is " + before);
485         } catch (final IllegalArgumentException iax) {
486             // expected
487         }
488     }
489 
490     @Test
491     public void testCstr1() {
492         final HttpRoute route = new HttpRoute(TARGET2);
493         final HttpRoute should = new HttpRoute
494             (TARGET2, null, (HttpHost[]) null, false,
495              TunnelType.PLAIN, LayerType.PLAIN);
496         Assert.assertEquals("bad convenience route", route, should);
497     }
498 
499     @Test
500     public void testCstr3() {
501         // test convenience constructor with 3 arguments
502         HttpRoute route = new HttpRoute(TARGET2, LOCAL61, false);
503         HttpRoute should = new HttpRoute
504             (TARGET2, LOCAL61, (HttpHost[]) null, false,
505              TunnelType.PLAIN, LayerType.PLAIN);
506         Assert.assertEquals("bad convenience route 3/insecure", route, should);
507 
508         route = new HttpRoute(TARGET2, null, true);
509         should = new HttpRoute(TARGET2, null, (HttpHost[]) null, true,
510                                TunnelType.PLAIN, LayerType.PLAIN);
511         Assert.assertEquals("bad convenience route 3/secure", route, should);
512     }
513 
514     @SuppressWarnings("unused")
515     @Test
516     public void testCstr4() {
517         // test convenience constructor with 4 arguments
518         HttpRoute route = new HttpRoute(TARGET2, null, PROXY2, false);
519         HttpRoute should = new HttpRoute
520             (TARGET2, null, new HttpHost[]{ PROXY2 }, false,
521              TunnelType.PLAIN, LayerType.PLAIN);
522         Assert.assertEquals("bad convenience route 4/insecure", route, should);
523 
524         route = new HttpRoute(TARGET2, LOCAL42, PROXY1, true);
525         should = new HttpRoute
526             (TARGET2, LOCAL42, new HttpHost[]{ PROXY1 }, true,
527              TunnelType.TUNNELLED, LayerType.LAYERED);
528         Assert.assertEquals("bad convenience route 4/secure", route, should);
529 
530         // this constructor REQUIRES a proxy to be specified
531         try {
532             new HttpRoute(TARGET1, LOCAL61, null, false);
533             Assert.fail("missing proxy not detected");
534         } catch (final IllegalArgumentException iax) {
535             // expected
536         }
537     }
538 
539     @Test
540     public void testCstr6() {
541         // test convenience constructor with 6 arguments
542         HttpRoute route = new HttpRoute
543             (TARGET2, null, PROXY2, true,
544              TunnelType.TUNNELLED, LayerType.PLAIN);
545         HttpRoute should = new HttpRoute
546             (TARGET2, null, new HttpHost[]{ PROXY2 }, true,
547              TunnelType.TUNNELLED, LayerType.PLAIN);
548         Assert.assertEquals("bad convenience route 6/proxied", route, should);
549 
550         route = new HttpRoute
551             (TARGET2, null, (HttpHost) null, true,
552              TunnelType.PLAIN, LayerType.LAYERED);
553         should = new HttpRoute
554             (TARGET2, null, (HttpHost[]) null, true,
555              TunnelType.PLAIN, LayerType.LAYERED);
556         Assert.assertEquals("bad convenience route 6/direct", route, should);
557 
558         // handling of null vs. empty chain is checked in the equals tests
559     }
560 
561     @Test
562     public void testImmutable() throws CloneNotSupportedException {
563 
564         final HttpHost[] proxies = new HttpHost[]{ PROXY1, PROXY2, PROXY3 };
565         final HttpRoute route1 = new HttpRoute(TARGET1, null, proxies, false,
566                                          TunnelType.PLAIN, LayerType.PLAIN);
567         final HttpRoute route2 = (HttpRoute) route1.clone();
568         final HttpRoute route3 = new HttpRoute(TARGET1, null,
569                                          proxies.clone(), false,
570                                          TunnelType.PLAIN, LayerType.PLAIN);
571 
572         // modify the array that was passed to the constructor of route1
573         proxies[1] = PROXY3;
574         proxies[2] = PROXY2;
575 
576         Assert.assertEquals("route differs from clone", route2, route1);
577         Assert.assertEquals("route was modified", route3, route1);
578     }
579 
580 }