1 package org.apache.maven.wagon.providers.http;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import static org.hamcrest.CoreMatchers.instanceOf;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertThat;
27 import static org.junit.Assert.assertTrue;
28 import static org.junit.Assert.fail;
29
30 import java.io.File;
31 import java.io.IOException;
32 import java.io.InterruptedIOException;
33 import java.lang.reflect.Field;
34 import java.net.ConnectException;
35 import java.net.MalformedURLException;
36 import java.net.URL;
37 import java.net.URLClassLoader;
38 import java.net.UnknownHostException;
39 import java.util.ArrayList;
40 import java.util.Collection;
41 import java.util.Set;
42
43 import javax.net.ssl.SSLException;
44
45 import org.apache.http.client.HttpRequestRetryHandler;
46 import org.apache.http.impl.client.CloseableHttpClient;
47 import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
48 import org.apache.http.impl.execchain.RedirectExec;
49 import org.apache.http.impl.execchain.RetryExec;
50 import org.apache.maven.wagon.InputData;
51 import org.apache.maven.wagon.repository.Repository;
52 import org.apache.maven.wagon.resource.Resource;
53 import org.apache.maven.wagon.shared.http.AbstractHttpClientWagon;
54 import org.junit.Test;
55
56 public class AbstractHttpClientWagonTest
57 {
58 @Test
59 public void test()
60 throws Exception
61 {
62 AbstractHttpClientWagon wagon = new AbstractHttpClientWagon()
63 {
64 };
65
66 Repository repository = new Repository( "central", "http://repo.maven.apache.org/maven2" );
67
68 wagon.connect( repository );
69
70 Resource resource = new Resource();
71
72 resource.setName( "junit/junit/maven-metadata.xml" );
73
74 InputData inputData = new InputData();
75
76 inputData.setResource( resource );
77
78 wagon.fillInputData( inputData );
79
80 wagon.disconnect();
81 }
82
83 @Test
84 public void retryableConfigurationDefaultTest() throws Exception
85 {
86 doTestHttpClient( new Runnable()
87 {
88 @Override
89 public void run()
90 {
91 final HttpRequestRetryHandler handler = getCurrentHandler();
92 assertNotNull( handler );
93 assertThat( handler, instanceOf( DefaultHttpRequestRetryHandler.class ) );
94 final DefaultHttpRequestRetryHandler impl = DefaultHttpRequestRetryHandler.class.cast(handler);
95 assertEquals( 3, impl.getRetryCount() );
96 assertFalse( impl.isRequestSentRetryEnabled() );
97 }
98 });
99 }
100
101 @Test
102 public void retryableConfigurationCountTest() throws Exception
103 {
104 doTestHttpClient( new Runnable()
105 {
106 @Override
107 public void run()
108 {
109 System.setProperty( "maven.wagon.http.retryHandler.class", "default" );
110 System.setProperty( "maven.wagon.http.retryHandler.count", "5" );
111
112 final HttpRequestRetryHandler handler = getCurrentHandler();
113 assertNotNull( handler );
114 assertThat( handler, instanceOf( DefaultHttpRequestRetryHandler.class ) );
115 final DefaultHttpRequestRetryHandler impl = DefaultHttpRequestRetryHandler.class.cast(handler);
116 assertEquals( 5, impl.getRetryCount() );
117 assertFalse( impl.isRequestSentRetryEnabled() );
118 }
119 });
120 }
121
122 @Test
123 public void retryableConfigurationSentTest() throws Exception
124 {
125 doTestHttpClient( new Runnable()
126 {
127 @Override
128 public void run()
129 {
130 System.setProperty( "maven.wagon.http.retryHandler.class", "default" );
131 System.setProperty( "maven.wagon.http.retryHandler.requestSentEnabled", "true" );
132
133 final HttpRequestRetryHandler handler = getCurrentHandler();
134 assertNotNull( handler );
135 assertThat( handler, instanceOf( DefaultHttpRequestRetryHandler.class ) );
136 final DefaultHttpRequestRetryHandler impl = DefaultHttpRequestRetryHandler.class.cast(handler);
137 assertEquals( 3, impl.getRetryCount() );
138 assertTrue( impl.isRequestSentRetryEnabled() );
139 }
140 });
141 }
142
143 @Test
144 public void retryableConfigurationExceptionsTest() throws Exception
145 {
146 doTestHttpClient( new Runnable()
147 {
148 @Override
149 public void run()
150 {
151 System.setProperty( "maven.wagon.http.retryHandler.class", "default" );
152 System.setProperty( "maven.wagon.http.retryHandler.nonRetryableClasses", IOException.class.getName() );
153
154 final HttpRequestRetryHandler handler = getCurrentHandler();
155 assertNotNull( handler );
156 assertThat( handler, instanceOf( DefaultHttpRequestRetryHandler.class ) );
157 final DefaultHttpRequestRetryHandler impl = DefaultHttpRequestRetryHandler.class.cast(handler);
158 assertEquals( 3, impl.getRetryCount() );
159 assertFalse( impl.isRequestSentRetryEnabled() );
160
161 try
162 {
163 final Field nonRetriableClasses = handler.getClass().getSuperclass()
164 .getDeclaredField( "nonRetriableClasses" );
165 if ( !nonRetriableClasses.isAccessible() )
166 {
167 nonRetriableClasses.setAccessible(true);
168 }
169 final Set<?> exceptions = Set.class.cast( nonRetriableClasses.get(handler) );
170 assertEquals( 1, exceptions.size() );
171 assertTrue( exceptions.contains( IOException.class ) );
172 }
173 catch ( final Exception e )
174 {
175 fail( e.getMessage() );
176 }
177 }
178 });
179 }
180
181 private HttpRequestRetryHandler getCurrentHandler()
182 {
183 try
184 {
185 final Class<?> impl = Thread.currentThread().getContextClassLoader().loadClass(
186 "org.apache.maven.wagon.shared.http.AbstractHttpClientWagon" );
187
188 final CloseableHttpClient httpClient = CloseableHttpClient.class.cast(
189 impl.getMethod("getHttpClient").invoke(null) );
190
191 final Field redirectExec = httpClient.getClass().getDeclaredField( "execChain" );
192 if ( !redirectExec.isAccessible() )
193 {
194 redirectExec.setAccessible( true );
195 }
196 final RedirectExec redirectExecInstance = RedirectExec.class.cast(
197 redirectExec.get( httpClient ) );
198
199 final Field requestExecutor = redirectExecInstance.getClass().getDeclaredField( "requestExecutor" );
200 if ( !requestExecutor.isAccessible() )
201 {
202 requestExecutor.setAccessible( true );
203 }
204 final RetryExec requestExecutorInstance = RetryExec.class.cast(
205 requestExecutor.get( redirectExecInstance ) );
206
207 final Field retryHandler = requestExecutorInstance.getClass().getDeclaredField( "retryHandler" );
208 if ( !retryHandler.isAccessible() )
209 {
210 retryHandler.setAccessible( true );
211 }
212 return HttpRequestRetryHandler.class.cast( retryHandler.get( requestExecutorInstance ) );
213 }
214 catch ( final Exception e )
215 {
216 throw new IllegalStateException(e);
217 }
218 }
219
220 private void doTestHttpClient( final Runnable test ) throws Exception
221 {
222 final String classpath = System.getProperty( "java.class.path" );
223 final String[] paths = classpath.split( File.pathSeparator );
224 final Collection<URL> urls = new ArrayList<>( paths.length );
225 for ( final String path : paths )
226 {
227 try
228 {
229 urls.add( new File( path ).toURI().toURL() );
230 }
231 catch ( final MalformedURLException e )
232 {
233 fail( e.getMessage() );
234 }
235 }
236 final URLClassLoader loader = new URLClassLoader( urls.toArray( new URL[ paths.length ] ) , new ClassLoader()
237 {
238 @Override
239 protected Class<?> loadClass( final String name, final boolean resolve ) throws ClassNotFoundException
240 {
241 if ( name.startsWith( "org.apache.maven.wagon.shared.http" ) )
242 {
243 throw new ClassNotFoundException( name );
244 }
245 return super.loadClass( name, resolve );
246 }
247 });
248 final Thread thread = Thread.currentThread();
249 final ClassLoader contextClassLoader = thread.getContextClassLoader();
250 thread.setContextClassLoader( loader );
251
252 final String originalClass = System.getProperty( "maven.wagon.http.retryHandler.class", "default" );
253 final String originalSentEnabled = System.getProperty(
254 "maven.wagon.http.retryHandler.requestSentEnabled", "false" );
255 final String originalCount = System.getProperty( "maven.wagon.http.retryHandler.count", "3" );
256 final String originalExceptions = System.getProperty( "maven.wagon.http.retryHandler.nonRetryableClasses",
257 InterruptedIOException.class.getName() + ","
258 + UnknownHostException.class.getName() + ","
259 + ConnectException.class.getName() + ","
260 + SSLException.class.getName());
261 try
262 {
263 test.run();
264 }
265 finally
266 {
267 loader.close();
268 thread.setContextClassLoader( contextClassLoader );
269 System.setProperty( "maven.wagon.http.retryHandler.class", originalClass );
270 System.setProperty( "maven.wagon.http.retryHandler.requestSentEnabled", originalSentEnabled );
271 System.setProperty( "maven.wagon.http.retryHandler.count", originalCount );
272 System.setProperty( "maven.wagon.http.retryHandler.nonRetryableClasses", originalExceptions );
273 }
274 }
275 }