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