001package org.apache.maven.wagon.providers.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.ResourceDoesNotExistException;
023import org.apache.maven.wagon.StreamingWagon;
024import org.apache.maven.wagon.TransferFailedException;
025import org.apache.maven.wagon.WagonException;
026import org.apache.maven.wagon.authorization.AuthorizationException;
027import org.apache.maven.wagon.http.HttpWagonTestCase;
028import org.codehaus.plexus.util.StringUtils;
029
030import javax.servlet.http.HttpServletResponse;
031import java.io.FileNotFoundException;
032import java.io.IOException;
033import java.util.Properties;
034
035/**
036 * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a>
037 *
038 */
039public class LightweightHttpWagonTest
040    extends HttpWagonTestCase
041{
042    protected String getProtocol()
043    {
044        return "http";
045    }
046
047    protected String getTestRepositoryUrl()
048    {
049        return getProtocol() + "://localhost:" + getTestRepositoryPort() + "/";
050    }
051
052    protected void setHttpConfiguration( StreamingWagon wagon, Properties headers, Properties params )
053    {
054        ( (LightweightHttpWagon) wagon ).setHttpHeaders( headers );
055    }
056
057    @Override
058    protected boolean supportPreemptiveAuthenticationGet()
059    {
060        return false;
061    }
062
063    @Override
064    protected boolean supportPreemptiveAuthenticationPut()
065    {
066        return false;
067    }
068
069    @Override
070    protected boolean supportProxyPreemptiveAuthentication()
071    {
072        return false;
073    }
074
075    @Override
076    protected void verifyWagonExceptionMessage( Exception e, int forStatusCode, String forUrl, String forReasonPhrase )
077    {
078
079        // HttpUrlConnection prevents direct API access to the response code or reasonPhrase for any
080        // status code >= 400. So all we can do is check WagonException wraps the HttpUrlConnection
081        // thrown IOException / FileNotFoundException as a cause, if cause is not null
082
083        assertNotNull( e );
084        try
085        {
086            assertTrue( "only verify instances of WagonException", e instanceof WagonException );
087
088            String assertMessageForBadMessage = "exception message not described properly: ";
089            switch ( forStatusCode )
090            {
091                case HttpServletResponse.SC_GONE:
092                case HttpServletResponse.SC_NOT_FOUND:
093                    assertTrue( "404 or 410 should throw ResourceDoesNotExistException",
094                            e instanceof ResourceDoesNotExistException );
095
096                    if ( e.getCause() != null )
097                    {
098                        assertTrue( "ResourceDoesNotExistException should have the expected cause",
099                                e.getCause() instanceof FileNotFoundException );
100                        // the status code and reason phrase cannot always be learned due to implementation limitations
101                        // which means the message may not include them
102                        assertEquals( assertMessageForBadMessage, "resource missing at " + forUrl, e.getMessage() );
103                    }
104                    else
105                    {
106                        assertEquals( assertMessageForBadMessage, "resource missing at " + forUrl
107                                + ", status: " + forStatusCode + " " + forReasonPhrase, e.getMessage() );
108                    }
109
110                    break;
111
112                case HttpServletResponse.SC_FORBIDDEN:
113                    assertTrue( "403 Forbidden throws AuthorizationException",
114                            e instanceof AuthorizationException );
115
116                    assertEquals( assertMessageForBadMessage, "authorization failed for " + forUrl + ", status: 403"
117                            + ( StringUtils.isEmpty( forReasonPhrase ) ? " Forbidden" : ( " " + forReasonPhrase ) ),
118                            e.getMessage() );
119                    break;
120
121                case HttpServletResponse.SC_UNAUTHORIZED:
122                    assertTrue( "401 Unauthorized throws AuthorizationException",
123                            e instanceof AuthorizationException );
124
125                    assertEquals( assertMessageForBadMessage, "authentication failed for " + forUrl + ", status: 401"
126                                    + ( StringUtils.isEmpty( forReasonPhrase ) ? " Unauthorized" :
127                                    ( " " + forReasonPhrase ) ),
128                            e.getMessage() );
129                    break;
130
131                default:
132                    assertTrue( "general exception must be TransferFailedException",
133                            e instanceof TransferFailedException );
134                    assertTrue( "expected status code for transfer failures should be >= 400, but none of "
135                                    + " the already handled codes",
136                            forStatusCode >= HttpServletResponse.SC_BAD_REQUEST );
137
138                    if ( e.getCause() != null )
139                    {
140                        assertTrue( "TransferFailedException should have the original cause for diagnosis",
141                                    e.getCause() instanceof IOException );
142                    }
143
144                    // the status code and reason phrase cannot always be learned due to implementation limitations
145                    // so the message may not include them, but the implementation should use a consistent format
146                    assertTrue( "message should always include url",
147                            e.getMessage().startsWith( "transfer failed for " + forUrl ) );
148
149                    if ( e.getMessage().length() > ( "transfer failed for " + forUrl ).length() )
150                    {
151                        assertTrue( "message should include url and status code",
152                                e.getMessage().startsWith( "transfer failed for " + forUrl + ", status: " + forStatusCode ) );
153                    }
154
155                    if ( e.getMessage().length() > ( "transfer failed for " + forUrl + ", status: " + forStatusCode ).length() )
156                    {
157                        assertEquals( "message should include url and status code and reason phrase",
158                                "transfer failed for " + forUrl + ", status: " + forStatusCode + " " + forReasonPhrase,
159                                e.getMessage() );
160                    }
161
162                    break;
163            }
164
165        }
166        catch ( AssertionError assertionError )
167        {
168            logger.error( "Exception which failed assertions: ", e );
169            throw assertionError;
170        }
171    }
172
173}