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  package org.apache.hc.client5.http.impl.classic;
28  
29  
30  import org.apache.hc.client5.http.impl.routing.DistributedProxySelector;
31  import org.junit.jupiter.api.Test;
32  
33  import java.io.IOException;
34  import java.net.InetSocketAddress;
35  import java.net.Proxy;
36  import java.net.ProxySelector;
37  import java.net.SocketAddress;
38  import java.net.URI;
39  import java.util.Arrays;
40  import java.util.Collections;
41  import java.util.List;
42  
43  import static org.junit.jupiter.api.Assertions.assertEquals;
44  import static org.junit.jupiter.api.Assertions.assertThrows;
45  import static org.mockito.ArgumentMatchers.any;
46  import static org.mockito.Mockito.mock;
47  import static org.mockito.Mockito.never;
48  import static org.mockito.Mockito.verify;
49  import static org.mockito.Mockito.when;
50  
51  class DistributedProxySelectorTest {
52  
53      @Test
54      void testConstructorThrowsExceptionWhenNullSelectors() {
55          assertThrows(IllegalArgumentException.class, () -> new DistributedProxySelector(null));
56      }
57  
58      @Test
59      void testConstructorThrowsExceptionWhenEmptySelectors() {
60          assertThrows(IllegalArgumentException.class, () -> new DistributedProxySelector(Collections.emptyList()));
61      }
62  
63      @Test
64      void testSelectReturnsProxyFromFirstSelector() {
65          final ProxySelector selector1 = new ProxySelector() {
66              @Override
67              public List<Proxy> select(final URI uri) {
68                  return Arrays.asList(
69                          new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy1.example.com", 8080)),
70                          new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy2.example.com", 8080))
71                  );
72              }
73  
74              @Override
75              public void connectFailed(final URI uri, final SocketAddress sa, final IOException ioe) {
76              }
77          };
78  
79          final ProxySelector selector2 = new ProxySelector() {
80              @Override
81              public List<Proxy> select(final URI uri) {
82                  return Collections.singletonList(
83                          new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy3.example.com", 8080))
84                  );
85              }
86  
87              @Override
88              public void connectFailed(final URI uri, final SocketAddress sa, final IOException ioe) {
89              }
90          };
91  
92          final DistributedProxySelector failoverSelector = new DistributedProxySelector(Arrays.asList(selector1, selector2));
93  
94          final URI uri = URI.create("http://example.com");
95          final List<Proxy> proxies = failoverSelector.select(uri);
96          assertEquals(2, proxies.size());
97          assertEquals("proxy1.example.com", ((InetSocketAddress) proxies.get(0).address()).getHostName());
98          assertEquals("proxy2.example.com", ((InetSocketAddress) proxies.get(1).address()).getHostName());
99      }
100 
101     @Test
102     void testSelectReturnsProxyFromSecondSelector() {
103         final ProxySelector selector1 = new ProxySelector() {
104             @Override
105             public List<Proxy> select(final URI uri) {
106                 return Collections.emptyList();
107             }
108 
109             @Override
110             public void connectFailed(final URI uri, final SocketAddress sa, final IOException ioe) {
111             }
112         };
113 
114         final ProxySelector selector2 = new ProxySelector() {
115             @Override
116             public List<Proxy> select(final URI uri) {
117                 return Collections.singletonList(
118                         new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy3.example.com", 8080))
119                 );
120             }
121 
122             @Override
123             public void connectFailed(final URI uri, final SocketAddress sa, final IOException ioe) {
124             }
125         };
126 
127         final DistributedProxySelector failoverSelector = new DistributedProxySelector(Arrays.asList(selector1, selector2));
128 
129         final URI uri = URI.create("http://example.com");
130         final List<Proxy> proxies = failoverSelector.select(uri);
131         assertEquals(1, proxies.size());
132         assertEquals("proxy3.example.com", ((InetSocketAddress) proxies.get(0).address()).getHostName());
133     }
134 
135     @Test
136     void testSelectReturnsProxyFromThirdSelector() {
137         final ProxySelector selector1 = new ProxySelector() {
138             @Override
139             public List<Proxy> select(final URI uri) {
140                 return Collections.emptyList();
141             }
142 
143             @Override
144             public void connectFailed(final URI uri, final SocketAddress sa, final IOException ioe) {
145             }
146         };
147 
148         final ProxySelector selector2 = mock(ProxySelector.class); // Create a mock object for ProxySelector
149 
150         when(selector2.select(any(URI.class))).thenReturn(Collections.singletonList(
151                 new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy3.example.com", 8080))
152         ));
153 
154         final DistributedProxySelector proxySelector = new DistributedProxySelector(Arrays.asList(selector1, selector2));
155 
156         final URI uri = URI.create("http://example.com");
157         final List<Proxy> proxies = proxySelector.select(uri);
158 
159         // Assertions
160         assertEquals(1, proxies.size(), "Expecting one proxy to be returned");
161         assertEquals("proxy3.example.com", ((InetSocketAddress) proxies.get(0).address()).getHostName(), "Expecting proxy3.example.com to be returned");
162 
163         // Verify that selector2's connectFailed() method is called when a connection fails
164         final SocketAddress sa = new InetSocketAddress("proxy3.example.com", 8080);
165         final IOException ioe = new IOException("Connection refused");
166         proxySelector.connectFailed(uri, sa, ioe);
167         verify(selector2, never()).connectFailed(uri, sa, ioe);
168     }
169 
170     @Test
171     void testSelectReturnsProxyFromSecondSelectorWhenFirstSelectorReturnsEmptyList() {
172         final ProxySelector selector1 = new ProxySelector() {
173             @Override
174             public List<Proxy> select(final URI uri) {
175                 return Collections.emptyList();
176             }
177 
178             @Override
179             public void connectFailed(final URI uri, final SocketAddress sa, final IOException ioe) {
180             }
181         };
182 
183         final ProxySelector selector2 = new ProxySelector() {
184             @Override
185             public List<Proxy> select(final URI uri) {
186                 return Collections.singletonList(
187                         new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy3.example.com", 8080))
188                 );
189             }
190 
191             @Override
192             public void connectFailed(final URI uri, final SocketAddress sa, final IOException ioe) {
193             }
194         };
195 
196         final DistributedProxySelector failoverSelector = new DistributedProxySelector(Arrays.asList(selector1, selector2));
197 
198         final URI uri = URI.create("http://example.com");
199         final List<Proxy> proxies = failoverSelector.select(uri);
200         assertEquals(1, proxies.size());
201         assertEquals("proxy3.example.com", ((InetSocketAddress) proxies.get(0).address()).getHostName());
202     }
203 
204     @Test
205     void testSelectHandlesException() {
206         final ProxySelector exceptionThrowingSelector = new ProxySelector() {
207             @Override
208             public List<Proxy> select(final URI uri) {
209                 throw new RuntimeException("Exception for testing");
210             }
211 
212             @Override
213             public void connectFailed(final URI uri, final SocketAddress sa, final IOException ioe) {
214             }
215         };
216 
217         final ProxySelector workingSelector = new ProxySelector() {
218             @Override
219             public List<Proxy> select(final URI uri) {
220                 return Collections.singletonList(
221                         new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.example.com", 8080))
222                 );
223             }
224 
225             @Override
226             public void connectFailed(final URI uri, final SocketAddress sa, final IOException ioe) {
227             }
228         };
229 
230         final DistributedProxySelector distributedSelector = new DistributedProxySelector(Arrays.asList(exceptionThrowingSelector, workingSelector));
231 
232         final URI uri = URI.create("http://example.com");
233         final List<Proxy> proxies = distributedSelector.select(uri);
234         assertEquals(1, proxies.size());
235         assertEquals("proxy.example.com", ((InetSocketAddress) proxies.get(0).address()).getHostName());
236     }
237 }