001package org.apache.maven.wagon.tck.http;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.maven.wagon.ConnectionException;
023import org.apache.maven.wagon.ResourceDoesNotExistException;
024import org.apache.maven.wagon.StreamWagon;
025import org.apache.maven.wagon.TransferFailedException;
026import org.apache.maven.wagon.authentication.AuthenticationException;
027import org.apache.maven.wagon.authentication.AuthenticationInfo;
028import org.apache.maven.wagon.authorization.AuthorizationException;
029import org.apache.maven.wagon.proxy.ProxyInfo;
030import org.apache.maven.wagon.tck.http.fixture.ErrorCodeServlet;
031import org.apache.maven.wagon.tck.http.fixture.LatencyServlet;
032import org.apache.maven.wagon.tck.http.fixture.ProxyConnectionVerifierFilter;
033import org.apache.maven.wagon.tck.http.fixture.RedirectionServlet;
034import org.apache.maven.wagon.tck.http.fixture.ServerFixture;
035import org.apache.maven.wagon.tck.http.fixture.ServletExceptionServlet;
036import org.apache.maven.wagon.tck.http.util.ValueHolder;
037import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
038import org.junit.Ignore;
039import org.junit.Test;
040
041import javax.servlet.Servlet;
042import javax.servlet.http.HttpServletResponse;
043import java.io.File;
044import java.io.IOException;
045
046import static junit.framework.Assert.assertTrue;
047import static junit.framework.Assert.fail;
048import static org.apache.maven.wagon.tck.http.Assertions.NO_RESPONSE_STATUS_CODE;
049import static org.apache.maven.wagon.tck.http.Assertions.assertFileContentsFromResource;
050import static org.apache.maven.wagon.tck.http.Assertions.assertWagonExceptionMessage;
051
052/**
053 * 
054 */
055public class GetWagonTests
056    extends HttpWagonTests
057{
058    private static final int TWO_SECONDS = 2000;
059    private static final int ONE_MINUTE = 60000;
060
061    @Test
062    public void basic()
063        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
064        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
065    {
066        testSuccessfulGet( "base.txt" );
067    }
068
069    @Test
070    @Ignore( "FIX ME!" )
071    public void proxied()
072        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
073        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
074    {
075        getServerFixture().addFilter( "*", new ProxyConnectionVerifierFilter() );
076
077        ProxyInfo info = newProxyInfo();
078        if ( !initTest( null, info ) )
079        {
080            return;
081        }
082
083        File target = newTempFile();
084        getWagon().get( "base.txt", target );
085
086        assertFileContentsFromResource( ServerFixture.SERVER_ROOT_RESOURCE_PATH, "base.txt", target,
087                                        "Downloaded file doesn't match original." );
088    }
089
090    @Test
091    public void highLatencyHighTimeout()
092        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
093        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
094    {
095        getServerFixture().addServlet( "/slow/*", new LatencyServlet( TWO_SECONDS ) );
096        testSuccessfulGet( "slow/large.txt", "large.txt" );
097    }
098
099    @Test
100    public void highLatencyLowTimeout()
101        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
102        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
103    {
104        Servlet servlet = new LatencyServlet( TWO_SECONDS );
105        getServerFixture().addServlet( "/slow/*", servlet );
106        testSuccessfulGet( "slow/large.txt", "large.txt" );
107    }
108
109    @Test
110    public void inifiniteLatencyTimeout()
111        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
112        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
113    {
114        if ( !isSupported() )
115        {
116            return;
117        }
118
119        final ValueHolder<TransferFailedException> holder = new ValueHolder<>( null );
120
121        Runnable r = new Runnable()
122        {
123            public void run()
124            {
125                Servlet servlet = new LatencyServlet( -1 );
126                addNotificationTarget( servlet );
127
128                getServerFixture().addServlet( "/infinite/*", servlet );
129                try
130                {
131                    if ( !initTest( null, null ) )
132                    {
133                        return;
134                    }
135
136                    if ( getWagon() instanceof StreamWagon )
137                    {
138                        logger.info( "Connection timeout is: " + getWagon().getTimeout() );
139                    }
140
141                    File target = newTempFile();
142                    getWagon().get( "infinite/", target );
143
144                    fail( "Should have failed to transfer due to transaction timeout." );
145                }
146                catch ( ConnectionException | AuthenticationException | ResourceDoesNotExistException
147                        | AuthorizationException | ComponentConfigurationException | IOException e )
148                {
149                    throw new IllegalStateException( e );
150                }
151                catch ( TransferFailedException e )
152                {
153                    // expected
154                    holder.setValue( e );
155                }
156            }
157        };
158
159        Thread t = new Thread( r );
160        t.start();
161
162        try
163        {
164            logger.info( "Waiting 60 seconds for wagon timeout." );
165            t.join( ONE_MINUTE );
166        }
167        catch ( InterruptedException e )
168        {
169            e.printStackTrace();
170        }
171
172        logger.info( "Interrupting thread." );
173        t.interrupt();
174
175        assertTrue( "TransferFailedException should have been thrown.", holder.getValue() != null );
176        assertWagonExceptionMessage( holder.getValue(), NO_RESPONSE_STATUS_CODE, getBaseUrl() + "infinite/",
177                "", null );
178    }
179
180    @Test
181    public void nonExistentHost()
182        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
183        ResourceDoesNotExistException, AuthorizationException
184    {
185        // we use a invalid localhost URL since some Internet Service Providers lately
186        // use funny 'search-DNS' which don't handle explicitly marked testing DNS properly.
187        // According to RFC-2606 .test, .invalid TLDs etc should work, but in practice it doesn't :(
188        if ( !initTest( "http://localhost:65520", null, null ) )
189        {
190            return;
191        }
192
193        File target = newTempFile();
194        try
195        {
196            getWagon().get( "base.txt", target );
197            fail( "Expected error related to host lookup failure." );
198        }
199        catch ( TransferFailedException e )
200        {
201            // expected
202            assertWagonExceptionMessage( e, NO_RESPONSE_STATUS_CODE,  "http://localhost:65520/base.txt",
203                    null, null );
204        }
205    }
206
207    @Test
208    public void oneLevelPermanentMove()
209        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
210        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
211    {
212        getServerFixture().addServlet( "/moved.txt",
213                                       new RedirectionServlet( HttpServletResponse.SC_MOVED_PERMANENTLY,
214                                                               "/base.txt" ) );
215
216        testSuccessfulGet( "moved.txt" );
217    }
218
219    @Test
220    public void oneLevelTemporaryMove()
221        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
222        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
223    {
224        getServerFixture().addServlet( "/moved.txt",
225                                       new RedirectionServlet( HttpServletResponse.SC_MOVED_TEMPORARILY,
226                                                               "/base.txt" ) );
227
228        testSuccessfulGet( "moved.txt" );
229    }
230
231    @Test
232    public void sixLevelPermanentMove()
233        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
234        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
235    {
236        String myPath = "moved.txt";
237        String targetPath = "/base.txt";
238
239        getServerFixture().addServlet( "/" + myPath + "/*",
240                                       new RedirectionServlet( HttpServletResponse.SC_MOVED_PERMANENTLY, myPath,
241                                                               targetPath, 6 ) );
242
243        testSuccessfulGet( myPath );
244    }
245
246    @Test
247    public void sixLevelTemporaryMove()
248        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
249        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
250    {
251        String myPath = "moved.txt";
252        String targetPath = "/base.txt";
253
254        getServerFixture().addServlet( "/" + myPath + "/*",
255                                       new RedirectionServlet( HttpServletResponse.SC_MOVED_TEMPORARILY, myPath,
256                                                               targetPath, 6 ) );
257
258        testSuccessfulGet( myPath );
259    }
260
261    @Test
262    public void infinitePermanentMove()
263        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
264        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
265    {
266        String myPath = "moved.txt";
267        String targetPath = "/base.txt";
268
269        getServerFixture().addServlet(
270                                       "/" + myPath,
271                                       new RedirectionServlet( HttpServletResponse.SC_MOVED_PERMANENTLY, myPath,
272                                                               targetPath, -1 ) );
273
274        try
275        {
276            testSuccessfulGet( myPath );
277            fail( "Expected failure as a result of too many redirects." );
278        }
279        catch ( TransferFailedException e )
280        {
281            // expected
282        }
283    }
284
285    @Test
286    public void infiniteTemporaryMove()
287        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
288        ResourceDoesNotExistException, AuthorizationException
289    {
290        String myPath = "moved.txt";
291        String targetPath = "/base.txt";
292
293        getServerFixture().addServlet(
294                                       "/" + myPath,
295                                       new RedirectionServlet( HttpServletResponse.SC_MOVED_TEMPORARILY, myPath,
296                                                               targetPath, -1 ) );
297
298        try
299        {
300            testSuccessfulGet( myPath );
301            fail( "Expected failure as a result of too many redirects." );
302        }
303        catch ( TransferFailedException e )
304        {
305            // expected
306        }
307    }
308
309    /**
310     * NOTE: This test depends on a {@link WagonTestCaseConfigurator} configuration to limit redirects to 20. In the
311     * case of the Sun HTTP implementation, this is the default limit.
312     */
313    @Test
314    @SuppressWarnings( "checkstyle:methodname" )
315    public void permanentMove_TooManyRedirects_limit20()
316        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
317        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
318    {
319        String myPath = "moved.txt";
320        String targetPath = "/base.txt";
321
322        getServerFixture().addServlet(
323                                       "/" + myPath,
324                                       new RedirectionServlet( HttpServletResponse.SC_MOVED_PERMANENTLY, myPath,
325                                                               targetPath, -1 ) );
326
327        try
328        {
329            testSuccessfulGet( myPath );
330            fail( "Expected failure as a result of too many redirects." );
331        }
332        catch ( TransferFailedException e )
333        {
334            // expected
335        }
336    }
337
338    /**
339     * NOTE: This test depends on a {@link WagonTestCaseConfigurator} configuration to limit redirects to 20. In the
340     * case of the Sun HTTP implementation, this is the default limit.
341     */
342    @Test
343    @SuppressWarnings( "checkstyle:methodname" )
344    public void temporaryMove_TooManyRedirects_limit20()
345        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
346        ResourceDoesNotExistException, AuthorizationException
347    {
348        String myPath = "moved.txt";
349        String targetPath = "/base.txt";
350
351        getServerFixture().addServlet(
352                                       "/" + myPath,
353                                       new RedirectionServlet( HttpServletResponse.SC_MOVED_TEMPORARILY, myPath,
354                                                               targetPath, -1 ) );
355
356        try
357        {
358            testSuccessfulGet( myPath );
359            fail( "Expected failure as a result of too many redirects." );
360        }
361        catch ( TransferFailedException e )
362        {
363            // expected
364        }
365    }
366
367    @Test
368    public void missing()
369        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
370        TransferFailedException, AuthorizationException
371    {
372        if ( !initTest( null, null ) )
373        {
374            return;
375        }
376
377        File target = newTempFile();
378        try
379        {
380            getWagon().get( "404.txt", target );
381            fail( "should have received a 404, meaning the resource doesn't exist." );
382        }
383        catch ( ResourceDoesNotExistException e )
384        {
385            // expected
386        }
387    }
388
389    @Test
390    public void error()
391        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
392        AuthorizationException, ResourceDoesNotExistException
393    {
394        testErrorHandling( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
395    }
396
397    @Test
398    public void proxyTimeout()
399        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
400        AuthorizationException, ResourceDoesNotExistException
401    {
402        testErrorHandling( HttpServletResponse.SC_GATEWAY_TIMEOUT );
403    }
404
405    @Test
406    public void forbidden()
407        throws ConnectionException, ComponentConfigurationException, IOException, ResourceDoesNotExistException,
408        TransferFailedException
409    {
410        AuthenticationInfo info = new AuthenticationInfo();
411        info.setUserName( "user" );
412        info.setPassword( "password" );
413
414        getServerFixture().addUser( info.getUserName(), "password" );
415
416        getServerFixture().addServlet( "/403.txt",
417                                       new ErrorCodeServlet( HttpServletResponse.SC_FORBIDDEN, "Expected 403" ) );
418
419        testAuthFailure( "403.txt", info );
420    }
421
422    @Test
423    public void successfulAuthentication()
424        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
425        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
426    {
427        AuthenticationInfo info = new AuthenticationInfo();
428        info.setUserName( "user" );
429        info.setPassword( "password" );
430
431        getServerFixture().addUser( info.getUserName(), info.getPassword() );
432
433        if ( !initTest( info, null ) )
434        {
435            return;
436        }
437
438        File target = newTempFile();
439        getWagon().get( "protected/base.txt", target );
440
441        assertFileContentsFromResource( ServerFixture.SERVER_ROOT_RESOURCE_PATH, "base.txt", target,
442                                        "Downloaded file doesn't match original." );
443    }
444
445    @Test
446    public void unsuccessfulAuthentication()
447        throws ConnectionException, ComponentConfigurationException, IOException, TransferFailedException,
448        ResourceDoesNotExistException
449    {
450        AuthenticationInfo info = new AuthenticationInfo();
451        info.setUserName( "user" );
452        info.setPassword( "password" );
453
454        getServerFixture().addUser( info.getUserName(), "anotherPassword" );
455
456        testAuthFailure( "protected/base.txt", info );
457    }
458
459    protected void testAuthFailure( final String path, final AuthenticationInfo info )
460        throws ConnectionException, ComponentConfigurationException, IOException, TransferFailedException,
461        ResourceDoesNotExistException
462    {
463        boolean authFailure = false;
464        try
465        {
466            if ( !initTest( info, null ) )
467            {
468                return;
469            }
470        }
471        catch ( AuthenticationException e )
472        {
473            // expected
474            authFailure = true;
475        }
476
477        File target = newTempFile();
478        try
479        {
480            getWagon().get( path, target );
481        }
482        catch ( AuthorizationException e )
483        {
484            // expected
485            authFailure = true;
486        }
487
488        assertTrue( "Authentication/Authorization should have failed.", authFailure );
489    }
490
491    protected void testSuccessfulGet( final String path )
492        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
493        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
494    {
495        testSuccessfulGet( path, "base.txt" );
496    }
497
498    protected void testSuccessfulGet( final String path, final String checkPath )
499        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
500        TransferFailedException, ResourceDoesNotExistException, AuthorizationException
501    {
502        if ( !initTest( null, null ) )
503        {
504            return;
505        }
506
507        if ( getWagon() instanceof StreamWagon )
508        {
509            logger.info( "Connection timeout is: " + getWagon().getTimeout() );
510        }
511
512        File target = newTempFile();
513        getWagon().get( path, target );
514
515        assertFileContentsFromResource( ServerFixture.SERVER_ROOT_RESOURCE_PATH, checkPath, target,
516                                        "Downloaded file doesn't match original." );
517    }
518
519    protected void testErrorHandling( final int code )
520        throws ConnectionException, AuthenticationException, ComponentConfigurationException, IOException,
521        AuthorizationException, ResourceDoesNotExistException
522    {
523        if ( code == HttpServletResponse.SC_INTERNAL_SERVER_ERROR )
524        {
525            getServerFixture().addServlet( "/" + code + ".txt", new ServletExceptionServlet( "Expected " + code ) );
526        }
527        else
528        {
529            getServerFixture().addServlet( "/" + code + ".txt", new ErrorCodeServlet( code, "Expected " + code ) );
530        }
531
532        if ( !initTest( null, null ) )
533        {
534            return;
535        }
536
537        File target = newTempFile();
538        try
539        {
540            getWagon().get( code + ".txt", target );
541            fail( "should have received a " + code + " error code, meaning the resource doesn't exist." );
542        }
543        catch ( TransferFailedException e )
544        {
545            // expected
546        }
547    }
548}