From 01863a58c8dfb5d1ab9f5081f8dfa5467b87045a Mon Sep 17 00:00:00 2001 From: John Casey Date: Tue, 19 May 2015 16:50:44 -0500 Subject: [PATCH 1/2] switch to using undertow-based http server fixture to try to work around NPE Vert.x was throwing in TravisCI environment. --- pom.xml | 20 + transports/httpclient/pom.xml | 18 +- .../htcli/internal/HttpDownload.java | 12 +- .../htcli/internal/HttpExistence.java | 15 +- .../transport/htcli/internal/HttpListing.java | 11 +- .../transport/htcli/internal/HttpPublish.java | 3 +- .../internal/util/TransferResponseUtils.java | 90 +++++ .../htcli/internal/HttpDownloadTest.java | 21 +- .../htcli/internal/HttpExistenceTest.java | 19 +- .../htcli/internal/HttpListTest.java | 38 +- .../htcli/testutil/ContentResponse.java | 80 ++++ .../htcli/testutil/HttpTestFixture.java | 16 +- .../htcli/testutil/TestHttpServer.java | 382 ++++++++++++------ 13 files changed, 550 insertions(+), 175 deletions(-) create mode 100644 transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/util/TransferResponseUtils.java create mode 100644 transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/testutil/ContentResponse.java diff --git a/pom.xml b/pom.xml index bd32ff8ed..d2594549c 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,7 @@ Red Hat, Inc. + 1.1.2.Final 0.14.0 1.4-SNAPSHOT @@ -178,6 +179,25 @@ cal10n-api 0.7.4 + + + io.undertow + undertow-core + ${undertowVersion} + test + + + io.undertow + undertow-servlet + ${undertowVersion} + test + + + org.jboss.spec.javax.servlet + jboss-servlet-api_3.0_spec + 1.0.1.Final + test + diff --git a/transports/httpclient/pom.xml b/transports/httpclient/pom.xml index c98378930..7b8eeedcf 100644 --- a/transports/httpclient/pom.xml +++ b/transports/httpclient/pom.xml @@ -37,12 +37,24 @@ jsoup - io.vertx - vertx-core + org.slf4j + jcl-over-slf4j + + + io.undertow + undertow-core + + + io.undertow + undertow-servlet + + + org.jboss.spec.javax.servlet + jboss-servlet-api_3.0_spec org.slf4j - jcl-over-slf4j + log4j-over-slf4j diff --git a/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpDownload.java b/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpDownload.java index 4b558fefb..498af9e4c 100644 --- a/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpDownload.java +++ b/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpDownload.java @@ -35,6 +35,7 @@ import org.commonjava.maven.galley.model.TransferOperation; import org.commonjava.maven.galley.spi.transport.DownloadJob; import org.commonjava.maven.galley.transport.htcli.Http; +import org.commonjava.maven.galley.transport.htcli.internal.util.TransferResponseUtils; import org.commonjava.maven.galley.transport.htcli.model.HttpLocation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -144,16 +145,7 @@ private HttpResponse executeGet( final HttpGet request, final String url ) logger.debug( "GET {} : {}", line, url ); if ( sc != HttpStatus.SC_OK ) { - EntityUtils.consume( response.getEntity() ); - - if ( sc == HttpStatus.SC_NOT_FOUND ) - { - return null; - } - else - { - throw new TransferException( "HTTP request failed: {}", line ); - } + return TransferResponseUtils.handleUnsuccessfulResponse( request, response, url ); } else { diff --git a/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpExistence.java b/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpExistence.java index 8433f301d..bc55e7da3 100644 --- a/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpExistence.java +++ b/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpExistence.java @@ -25,6 +25,7 @@ import org.commonjava.maven.galley.TransferException; import org.commonjava.maven.galley.spi.transport.ExistenceJob; import org.commonjava.maven.galley.transport.htcli.Http; +import org.commonjava.maven.galley.transport.htcli.internal.util.TransferResponseUtils; import org.commonjava.maven.galley.transport.htcli.model.HttpLocation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -82,8 +83,6 @@ public TransferException getError() private boolean execute( final HttpHead request, final String url ) throws TransferException { - boolean result = false; - try { final HttpResponse response = http.getClient() @@ -93,14 +92,8 @@ private boolean execute( final HttpHead request, final String url ) logger.debug( "HEAD {} : {}", line, url ); if ( sc != HttpStatus.SC_OK ) { - if ( sc != HttpStatus.SC_NOT_FOUND ) - { - throw new TransferException( "HTTP request failed: {}", line ); - } - } - else - { - result = true; + TransferResponseUtils.handleUnsuccessfulResponse( request, response, url ); + return false; } } catch ( final ClientProtocolException e ) @@ -112,7 +105,7 @@ private boolean execute( final HttpHead request, final String url ) throw new TransferException( "Repository remote request failed for: {}. Reason: {}", e, url, e.getMessage() ); } - return result; + return true; } private void cleanup( final HttpHead request ) diff --git a/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpListing.java b/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpListing.java index 2b6d02ae6..6e5bdfb11 100644 --- a/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpListing.java +++ b/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpListing.java @@ -37,6 +37,7 @@ import org.commonjava.maven.galley.model.TransferOperation; import org.commonjava.maven.galley.spi.transport.ListingJob; import org.commonjava.maven.galley.transport.htcli.Http; +import org.commonjava.maven.galley.transport.htcli.internal.util.TransferResponseUtils; import org.commonjava.maven.galley.transport.htcli.model.HttpLocation; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -166,14 +167,8 @@ private InputStream executeGet( final HttpGet request, final String url ) logger.debug( "GET {} : {}", line, url ); if ( sc != HttpStatus.SC_OK ) { - if ( sc == HttpStatus.SC_NOT_FOUND ) - { - result = null; - } - else - { - throw new TransferException( "HTTP request failed: %s", line ); - } + TransferResponseUtils.handleUnsuccessfulResponse( request, response, url ); + result = null; } else { diff --git a/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpPublish.java b/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpPublish.java index 868e0349c..932bb4013 100644 --- a/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpPublish.java +++ b/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/HttpPublish.java @@ -28,6 +28,7 @@ import org.commonjava.maven.galley.TransferException; import org.commonjava.maven.galley.spi.transport.PublishJob; import org.commonjava.maven.galley.transport.htcli.Http; +import org.commonjava.maven.galley.transport.htcli.internal.util.TransferResponseUtils; import org.commonjava.maven.galley.transport.htcli.model.HttpLocation; import org.commonjava.maven.galley.util.ContentTypeUtils; import org.slf4j.Logger; @@ -114,7 +115,7 @@ private HttpResponse executePut( final HttpPut request, final String url ) if ( sc != HttpStatus.SC_OK && sc != HttpStatus.SC_CREATED ) { logger.warn( "{} : {}", line, url ); - throw new TransferException( "HTTP request failed: {}", line ); + return TransferResponseUtils.handleUnsuccessfulResponse( request, response, url, false ); } else { diff --git a/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/util/TransferResponseUtils.java b/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/util/TransferResponseUtils.java new file mode 100644 index 000000000..c3a43f8a8 --- /dev/null +++ b/transports/httpclient/src/main/java/org/commonjava/maven/galley/transport/htcli/internal/util/TransferResponseUtils.java @@ -0,0 +1,90 @@ +package org.commonjava.maven.galley.transport.htcli.internal.util; + +import static org.apache.commons.io.IOUtils.copy; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.StatusLine; +import org.apache.http.client.methods.AbstractExecutionAwareRequest; +import org.apache.http.util.EntityUtils; +import org.commonjava.maven.galley.TransferException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class TransferResponseUtils +{ + + private TransferResponseUtils() + { + } + + public static HttpResponse handleUnsuccessfulResponse( final AbstractExecutionAwareRequest request, + final HttpResponse response, final String url ) + throws TransferException + { + return handleUnsuccessfulResponse( request, response, url, true ); + } + + public static HttpResponse handleUnsuccessfulResponse( final AbstractExecutionAwareRequest request, + final HttpResponse response, final String url, + final boolean graceful404 ) + throws TransferException + { + final Logger logger = LoggerFactory.getLogger( TransferResponseUtils.class ); + + final StatusLine line = response.getStatusLine(); + InputStream in = null; + HttpEntity entity = null; + try + { + entity = response.getEntity(); + final int sc = line.getStatusCode(); + if ( graceful404 && sc == HttpStatus.SC_NOT_FOUND ) + { + return null; + } + else + { + ByteArrayOutputStream out = null; + if ( entity != null ) + { + in = entity.getContent(); + out = new ByteArrayOutputStream(); + copy( in, out ); + } + + throw new TransferException( "HTTP request failed: %s%s", line, ( out == null ? "" : "\n\n" + + new String( out.toByteArray() ) ) ); + } + } + catch ( final IOException e ) + { + request.abort(); + throw new TransferException( + "Error reading body of unsuccessful request.\nStatus: %s.\nURL: %s.\nReason: %s", + e, line, url, e.getMessage() ); + } + finally + { + IOUtils.closeQuietly( in ); + if ( entity != null ) + { + try + { + EntityUtils.consume( entity ); + } + catch ( final IOException e ) + { + logger.debug( "Failed to consume entity: " + e.getMessage(), e ); + } + } + } + } + +} diff --git a/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/internal/HttpDownloadTest.java b/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/internal/HttpDownloadTest.java index f840f4a1c..423bd358f 100644 --- a/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/internal/HttpDownloadTest.java +++ b/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/internal/HttpDownloadTest.java @@ -20,8 +20,6 @@ import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertThat; -import java.util.Map; - import org.commonjava.maven.galley.TransferException; import org.commonjava.maven.galley.model.ConcreteResource; import org.commonjava.maven.galley.model.Transfer; @@ -42,6 +40,9 @@ public void simpleRetrieveOfAvailableUrl() { final String fname = "simple-retrieval.html"; + fixture.getServer() + .expect( fixture.formatUrl( fname ), 200, fname ); + final String baseUri = fixture.getBaseUri(); final SimpleHttpLocation location = new SimpleHttpLocation( "test", baseUri, true, true, true, true, null ); final Transfer transfer = fixture.getTransfer( new ConcreteResource( location, fname ) ); @@ -60,10 +61,9 @@ public void simpleRetrieveOfAvailableUrl() assertThat( result.exists(), equalTo( true ) ); assertThat( transfer.exists(), equalTo( true ) ); - final Map accessesByPath = fixture.getAccessesByPath(); final String path = fixture.getUrlPath( url ); - assertThat( accessesByPath.get( path ), equalTo( 1 ) ); + assertThat( fixture.getAccessesFor( path ), equalTo( 1 ) ); } @Test @@ -89,10 +89,9 @@ public void simpleRetrieveOfMissingUrl() assertThat( result.exists(), equalTo( false ) ); assertThat( transfer.exists(), equalTo( false ) ); - final Map accessesByPath = fixture.getAccessesByPath(); final String path = fixture.getUrlPath( url ); - assertThat( accessesByPath.get( path ), equalTo( 1 ) ); + assertThat( fixture.getAccessesFor( path ), equalTo( 1 ) ); } @Test @@ -107,7 +106,8 @@ public void simpleRetrieveOfUrlWithError() final String url = fixture.formatUrl( fname ); final String error = "Test Error."; - fixture.registerException( fixture.getUrlPath( url ), error ); + final String path = fixture.getUrlPath( url ); + fixture.registerException( path, error ); assertThat( transfer.exists(), equalTo( false ) ); @@ -116,16 +116,15 @@ public void simpleRetrieveOfUrlWithError() final TransferException err = dl.getError(); assertThat( err, notNullValue() ); + assertThat( err.getMessage() - .endsWith( error ), equalTo( true ) ); + .contains( error ), equalTo( true ) ); assertThat( result, nullValue() ); assertThat( transfer.exists(), equalTo( false ) ); - final Map accessesByPath = fixture.getAccessesByPath(); - final String path = fixture.getUrlPath( url ); - assertThat( accessesByPath.get( path ), equalTo( 1 ) ); + assertThat( fixture.getAccessesFor( path ), equalTo( 1 ) ); } } diff --git a/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/internal/HttpExistenceTest.java b/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/internal/HttpExistenceTest.java index 4daafabcf..a620629fb 100644 --- a/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/internal/HttpExistenceTest.java +++ b/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/internal/HttpExistenceTest.java @@ -20,8 +20,6 @@ import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertThat; -import java.util.Map; - import org.commonjava.maven.galley.TransferException; import org.commonjava.maven.galley.transport.htcli.model.SimpleHttpLocation; import org.commonjava.maven.galley.transport.htcli.testutil.HttpTestFixture; @@ -40,9 +38,12 @@ public void simpleRetrieveOfAvailableUrl() { final String fname = "simple-retrieval.html"; + final String url = fixture.formatUrl( fname ); + fixture.getServer() + .expect( url, 200, fname ); + final String baseUri = fixture.getBaseUri(); final SimpleHttpLocation location = new SimpleHttpLocation( "test", baseUri, true, true, true, true, null ); - final String url = fixture.formatUrl( fname ); final HttpExistence dl = new HttpExistence( url, location, fixture.getHttp() ); final Boolean result = dl.call(); @@ -54,10 +55,9 @@ public void simpleRetrieveOfAvailableUrl() assertThat( result, equalTo( true ) ); - final Map accessesByPath = fixture.getAccessesByPath(); final String path = fixture.getUrlPath( url ); - assertThat( accessesByPath.get( path ), equalTo( 1 ) ); + assertThat( fixture.getAccessesFor( "HEAD", path ), equalTo( 1 ) ); } @Test @@ -83,10 +83,9 @@ public void simpleRetrieveOfMissingUrl() assertThat( result, notNullValue() ); assertThat( result, equalTo( false ) ); - final Map accessesByPath = fixture.getAccessesByPath(); final String path = fixture.getUrlPath( url ); - assertThat( accessesByPath.get( path ), equalTo( 1 ) ); + assertThat( fixture.getAccessesFor( "HEAD", path ), equalTo( 1 ) ); } @Test @@ -108,16 +107,12 @@ public void simpleRetrieveOfUrlWithError() final TransferException err = dl.getError(); assertThat( err, notNullValue() ); - assertThat( err.getMessage() - .endsWith( error ), equalTo( true ) ); - assertThat( result, notNullValue() ); assertThat( result, equalTo( false ) ); - final Map accessesByPath = fixture.getAccessesByPath(); final String path = fixture.getUrlPath( url ); - assertThat( accessesByPath.get( path ), equalTo( 1 ) ); + assertThat( fixture.getAccessesFor( "HEAD", path ), equalTo( 1 ) ); } } diff --git a/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/internal/HttpListTest.java b/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/internal/HttpListTest.java index 82f86bb8b..b40f8dae7 100644 --- a/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/internal/HttpListTest.java +++ b/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/internal/HttpListTest.java @@ -20,10 +20,12 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import java.io.InputStream; import java.util.Arrays; import java.util.List; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; import org.commonjava.maven.galley.model.ConcreteResource; import org.commonjava.maven.galley.model.ListingResult; import org.commonjava.maven.galley.model.Transfer; @@ -98,6 +100,10 @@ public void simpleCentralListing() final String listingFname = dir + ".listing.txt"; final String url = fixture.formatUrl( fname ); + final String body = getBody( fname ); + fixture.getServer() + .expect( url, 200, body ); + final SimpleHttpLocation location = new SimpleHttpLocation( "test", url, true, true, true, true, null ); final Transfer transfer = fixture.getTransfer( new ConcreteResource( location, listingFname ) ); @@ -106,9 +112,23 @@ public void simpleCentralListing() final ListingResult result = listing.call(); assertThat( listing.getError(), nullValue() ); + assertThat( result, notNullValue() ); + assertThat( result.getListing(), notNullValue() ); + + System.out.println( "Got listing\n\n " + StringUtils.join( result.getListing(), "\n " ) + "\n\n" ); assertTrue( Arrays.equals( centralbtm, result.getListing() ) ); } + private String getBody( final String fname ) + throws Exception + { + final InputStream stream = Thread.currentThread() + .getContextClassLoader() + .getResourceAsStream( "list-basic/" + fname ); + + return IOUtils.toString( stream ); + } + @Test public void simpleCentralListing_WriteListingFile() throws Exception @@ -118,6 +138,10 @@ public void simpleCentralListing_WriteListingFile() final String listingFname = dir + ".listing.txt"; final String url = fixture.formatUrl( fname ); + final String body = getBody( fname ); + fixture.getServer() + .expect( url, 200, body ); + final SimpleHttpLocation location = new SimpleHttpLocation( "test", url, true, true, true, true, null ); final Transfer transfer = fixture.getTransfer( new ConcreteResource( location, listingFname ) ); @@ -126,8 +150,10 @@ public void simpleCentralListing_WriteListingFile() final ListingResult result = listing.call(); assertThat( listing.getError(), nullValue() ); + assertThat( result, notNullValue() ); + assertThat( result.getListing(), notNullValue() ); assertTrue( Arrays.equals( centralbtm, result.getListing() ) ); - + final List lines = IOUtils.readLines( transfer.openInputStream() ); assertTrue( "Listing file written incorrectly!", lines.equals( Arrays.asList( centralbtm ) ) ); } @@ -175,7 +201,7 @@ public void simpleCentralListing_Error() assertThat( listing.getError(), notNullValue() ); assertTrue( listing.getError() .getMessage() - .endsWith( "Test Error" ) ); + .contains( "Test Error" ) ); } @Test @@ -187,6 +213,10 @@ public void simpleNexusListing() final String listingFname = dir + ".listing.txt"; final String url = fixture.formatUrl( fname ); + final String body = getBody( fname ); + fixture.getServer() + .expect( url, 200, body ); + final SimpleHttpLocation location = new SimpleHttpLocation( "test", url, true, true, true, true, null ); final Transfer transfer = fixture.getTransfer( new ConcreteResource( location, listingFname ) ); @@ -195,6 +225,8 @@ public void simpleNexusListing() final ListingResult result = listing.call(); assertThat( listing.getError(), nullValue() ); + assertThat( result, notNullValue() ); + assertThat( result.getListing(), notNullValue() ); assertTrue( Arrays.equals( nexusswitchyard, result.getListing() ) ); } @@ -241,6 +273,6 @@ public void simpleNexusListing_Error() assertThat( listing.getError(), notNullValue() ); assertTrue( listing.getError() .getMessage() - .endsWith( "Test Error" ) ); + .contains( "Test Error" ) ); } } diff --git a/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/testutil/ContentResponse.java b/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/testutil/ContentResponse.java new file mode 100644 index 000000000..024035713 --- /dev/null +++ b/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/testutil/ContentResponse.java @@ -0,0 +1,80 @@ +/** + * Copyright (C) 2011 Red Hat, Inc. (jdcasey@commonjava.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.commonjava.maven.galley.transport.htcli.testutil; + +import java.io.InputStream; + +public final class ContentResponse +{ + private final int code; + + private final InputStream bodyStream; + + private final String body; + + private final String path; + + private final String method; + + ContentResponse( final String method, final String path, final int code, final String body ) + { + this.method = method; + this.path = path; + this.code = code; + this.body = body; + this.bodyStream = null; + } + + ContentResponse( final String method, final String path, final int code, final InputStream bodyStream ) + { + this.method = method; + this.path = path; + this.code = code; + this.body = null; + this.bodyStream = bodyStream; + } + + public String method() + { + return method; + } + + public String path() + { + return path; + } + + public int code() + { + return code; + } + + public String body() + { + return body; + } + + public InputStream bodyStream() + { + return bodyStream; + } + + @Override + public String toString() + { + return "Expect (" + method + " " + path + "), and respond with code:" + code() + ", body:\n" + body(); + } +} \ No newline at end of file diff --git a/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/testutil/HttpTestFixture.java b/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/testutil/HttpTestFixture.java index ef5b30668..bd7e9ae26 100644 --- a/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/testutil/HttpTestFixture.java +++ b/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/testutil/HttpTestFixture.java @@ -91,7 +91,7 @@ public HttpTestFixture( final String baseResource ) @Override protected void after() { - server.shutdown(); + server.after(); folder.delete(); super.after(); } @@ -101,7 +101,7 @@ protected void before() throws Throwable { super.before(); - server.start(); + server.before(); } public TemporaryFolder getFolder() @@ -223,7 +223,7 @@ public void registerException( final String url, final String error ) server.registerException( url, error ); } - public Map getRegisteredErrors() + public Map getRegisteredErrors() { return server.getRegisteredErrors(); } @@ -238,4 +238,14 @@ public void setPassword( final PasswordEntry id, final String password ) { passwords.put( id, password ); } + + public Integer getAccessesFor( final String path ) + { + return server.getAccessesFor( path ); + } + + public Integer getAccessesFor( final String method, final String path ) + { + return server.getAccessesFor( method, path ); + } } diff --git a/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/testutil/TestHttpServer.java b/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/testutil/TestHttpServer.java index 9205a40cb..9b573a807 100644 --- a/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/testutil/TestHttpServer.java +++ b/transports/httpclient/src/test/java/org/commonjava/maven/galley/transport/htcli/testutil/TestHttpServer.java @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 Red Hat, Inc. (jdcasey@commonjava.org) + * Copyright (C) 2011 Red Hat, Inc. (jdcasey@commonjava.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,27 +15,38 @@ */ package org.commonjava.maven.galley.transport.htcli.testutil; -import java.io.ByteArrayOutputStream; +import static org.commonjava.maven.galley.util.PathUtils.normalize; +import io.undertow.Undertow; +import io.undertow.servlet.Servlets; +import io.undertow.servlet.api.DeploymentInfo; +import io.undertow.servlet.api.DeploymentManager; +import io.undertow.servlet.api.ServletInfo; +import io.undertow.servlet.util.ImmediateInstanceFactory; + import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.ServerSocket; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.Random; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.apache.commons.io.IOUtils; +import org.junit.rules.ExternalResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.vertx.java.core.Handler; -import org.vertx.java.core.Vertx; -import org.vertx.java.core.buffer.Buffer; -import org.vertx.java.core.http.HttpServerRequest; -import org.vertx.java.core.impl.DefaultVertx; public class TestHttpServer - implements Handler + extends ExternalResource { private static final int TRIES = 4; @@ -46,17 +57,13 @@ public class TestHttpServer private final int port; - private Vertx vertx; - - private final String baseResource; - - private final Map accessesByPath = new HashMap(); + private final ExpectationServlet servlet; - private final Map errors = new HashMap(); + private Undertow server; public TestHttpServer( final String baseResource ) { - this.baseResource = baseResource; + servlet = new ExpectationServlet( baseResource ); int port = -1; ServerSocket ss = null; @@ -82,7 +89,8 @@ public TestHttpServer( final String baseResource ) if ( port < 8000 ) { - throw new RuntimeException( "Failed to start test HTTP server. Cannot find open port in " + TRIES + " tries." ); + throw new RuntimeException( "Failed to start test HTTP server. Cannot find open port in " + TRIES + + " tries." ); } this.port = port; @@ -93,155 +101,303 @@ public int getPort() return port; } - public void shutdown() + @Override + public void after() { - if ( vertx != null ) + if ( server != null ) { - vertx.stop(); + server.stop(); + logger.info( "STOPPED Test HTTP Server on 127.0.0.1:" + port ); } } - public void start() + @Override + public void before() throws Exception { - vertx = new DefaultVertx(); - vertx.createHttpServer() - .requestHandler( this ) - .listen( port ); + final ServletInfo si = Servlets.servlet( "TEST", ExpectationServlet.class ) + .addMapping( "*" ) + .addMapping( "/*" ) + .setLoadOnStartup( 1 ); + + si.setInstanceFactory( new ImmediateInstanceFactory( servlet ) ); + + final DeploymentInfo di = new DeploymentInfo().addServlet( si ) + .setDeploymentName( "TEST" ) + .setContextPath( "/" ) + .setClassLoader( Thread.currentThread() + .getContextClassLoader() ); + + final DeploymentManager dm = Servlets.defaultContainer() + .addDeployment( di ); + dm.deploy(); + + server = Undertow.builder() + .setHandler( dm.start() ) + .addHttpListener( port, "127.0.0.1" ) + .build(); + + server.start(); + logger.info( "STARTED Test HTTP Server on 127.0.0.1:" + port ); } - public String formatUrl( final String subpath ) + public static final class ExpectationServlet + extends HttpServlet { - return String.format( "http://localhost:%s/%s/%s", port, baseResource, subpath ); - } + private final Logger logger = LoggerFactory.getLogger( getClass() ); - public String getBaseUri() - { - return String.format( "http://localhost:%s/%s", port, baseResource ); - } + private static final long serialVersionUID = 1L; - public String getUrlPath( final String url ) - throws MalformedURLException - { - return new URL( url ).getPath(); - } + private final String baseResource; - public Map getAccessesByPath() - { - return accessesByPath; - } + private final Map expectations = new HashMap(); - public Map getRegisteredErrors() - { - return errors; - } + private final Map accessesByPath = new HashMap(); - @Override - public void handle( final HttpServerRequest req ) - { - final String wholePath = req.path(); - String path = wholePath; - if ( path.length() > 1 ) + private final Map errors = new HashMap(); + + public ExpectationServlet() { - path = path.substring( 1 ); + logger.error( "Default constructor not actually supported!!!" ); + this.baseResource = "/"; } - final Integer i = accessesByPath.get( wholePath ); - if ( i == null ) + public ExpectationServlet( final String baseResource ) { - accessesByPath.put( wholePath, 1 ); + this.baseResource = baseResource; } - else + + public Map getAccessesByPath() { - accessesByPath.put( wholePath, i + 1 ); + return accessesByPath; } - if ( errors.containsKey( wholePath ) ) + public Map getRegisteredErrors() { - final String error = errors.get( wholePath ); - logger.error( "Returning registered error: {}", error ); - req.response() - .setStatusCode( 500 ) - .setStatusMessage( error ) - .end(); - return; + return errors; } - logger.info( "Looking for classpath resource: '{}'", path ); + public String getBaseResource() + { + return baseResource; + } - final URL url = Thread.currentThread() - .getContextClassLoader() - .getResource( path ); + public void registerException( final String method, final String path, final int code, final String error ) + { + final String key = key( method, path ); + logger.info( "Registering error: {}, code: {}, body:\n{}", key, code, error ); + this.errors.put( key, new ContentResponse( method, path, code, error ) ); + } - logger.info( "Classpath URL is: '{}'", url ); + public void expect( final String method, final String testUrl, final int responseCode, final String body ) + throws Exception + { + final URL url = new URL( testUrl ); + final String path = url.getPath(); - if ( url == null ) + final String key = key( method, path ); + logger.info( "Registering expectation: {}, code: {}, body:\n{}", key, responseCode, body ); + expectations.put( key, new ContentResponse( method, path, responseCode, body ) ); + } + + public void expect( final String method, final String testUrl, final int responseCode, + final InputStream bodyStream ) + throws Exception { - req.response() - .setStatusCode( 404 ) - .setStatusMessage( "Not found" ) - .end(); + final URL url = new URL( testUrl ); + final String path = url.getPath(); + + final String key = key( method, path ); + logger.info( "Registering expectation: {}, code: {}, body stream:\n{}", key, responseCode, bodyStream ); + expectations.put( key, new ContentResponse( method, path, responseCode, + bodyStream ) ); } - else + + @Override + protected void service( final HttpServletRequest req, final HttpServletResponse resp ) + throws ServletException, IOException { - final String method = req.method() - .toUpperCase(); + String wholePath; + try + { + wholePath = new URI( req.getRequestURI() ).getPath(); + } + catch ( final URISyntaxException e ) + { + throw new ServletException( "Cannot parse request URI", e ); + } - logger.info( "Method: '{}'", method ); - if ( "GET".equals( method ) ) + String path = wholePath; + if ( path.length() > 1 ) { - doGet( req, url ); + path = path.substring( 1 ); } - else if ( "HEAD".equals( method ) ) + + final String method = req.getMethod() + .toUpperCase(); + + final String key = key( method, wholePath ); + + logger.info( "Looking up expectation for: {}", key ); + + Integer i = accessesByPath.get( key ); + if ( i == null ) { - req.response() - .setStatusCode( 200 ) - .end(); + i = 1; } else { - req.response() - .setStatusCode( 400 ) - .setStatusMessage( "Method: " + method + " not supported by test fixture." ) - .end(); + i = i + 1; } - } - } - private void doGet( final HttpServerRequest req, final URL url ) - { - InputStream stream = null; - try - { - stream = url.openStream(); + logger.info( "Logging access for: {} (total: {})", key, i ); + accessesByPath.put( key, i ); + + if ( errors.containsKey( key ) ) + { + final ContentResponse error = errors.get( key ); + logger.error( "Returning registered error: {}", error ); + // resp.setStatus( error.code() ); + resp.sendError( error.code(), error.body() ); + + if ( error.body() != null ) + { + resp.getWriter() + .write( error.body() ); + } + else + { + logger.info( "Registered error doesn't contain a body." ); + } + + return; + } + + logger.info( "Looking for expectation: '{}'", key ); + final ContentResponse expectation = expectations.get( key ); + if ( expectation != null ) + { + logger.info( "Responding via registered expectation: {}", expectation ); + + resp.setStatus( expectation.code() ); - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - IOUtils.copy( stream, baos ); + if ( expectation.body() != null ) + { + resp.getWriter() + .write( expectation.body() ); + } + else if ( expectation.bodyStream() != null ) + { + IOUtils.copy( expectation.bodyStream(), resp.getOutputStream() ); + } - final int len = baos.toByteArray().length; - final Buffer buf = new Buffer( baos.toByteArray() ); - logger.info( "Send: {} bytes", len ); - req.response() - .putHeader( "Content-Length", Integer.toString( len ) ) - .end( buf ); + return; + } + + resp.setStatus( 404 ); } - catch ( final IOException e ) + + private String key( final String method, final String wholePath ) { - logger.error( String.format( "Failed to stream content for: %s. Reason: %s", url, e.getMessage() ), e ); - req.response() - .setStatusCode( 500 ) - .setStatusMessage( "FAIL: " + e.getMessage() ) - .end(); + return method.toUpperCase() + " " + wholePath; } - finally + + public Integer getAccessesFor( final String path ) + { + return getAccessesFor( "GET", path ); + } + + public Integer getAccessesFor( final String method, final String path ) { - IOUtils.closeQuietly( stream ); + final String key = key( method, path ); + final Integer result = accessesByPath.get( key ); + logger.info( "Got {} accesses for key: {}", result, key ); + return result; } + + } + + public String formatUrl( final String... subpath ) + { + return String.format( "http://127.0.0.1:%s/%s/%s", port, servlet.getBaseResource(), normalize( subpath ) ); + } + + public String getBaseUri() + { + return String.format( "http://127.0.0.1:%s/%s", port, servlet.getBaseResource() ); + } + + public String getUrlPath( final String url ) + throws MalformedURLException + { + return new URL( url ).getPath(); + } + + public Map getAccessesByPath() + { + return servlet.getAccessesByPath(); + } + + public Map getRegisteredErrors() + { + return servlet.getRegisteredErrors(); } public void registerException( final String url, final String error ) { - this.errors.put( url, error ); + servlet.registerException( "GET", url, 500, error ); + servlet.registerException( "HEAD", url, 500, error ); + } + + public void registerException( final String method, final String url, final String error ) + { + servlet.registerException( method, url, 500, error ); + } + + public void registerException( final String url, final String error, final int responseCode ) + { + servlet.registerException( "GET", url, responseCode, error ); + } + + public void registerException( final String method, final String url, final int responseCode, final String error ) + { + servlet.registerException( method, url, responseCode, error ); + } + + public void expect( final String testUrl, final int responseCode, final String body ) + throws Exception + { + servlet.expect( "GET", testUrl, responseCode, body ); + servlet.expect( "HEAD", testUrl, responseCode, (String) null ); + } + + public void expect( final String method, final String testUrl, final int responseCode, final String body ) + throws Exception + { + servlet.expect( method, testUrl, responseCode, body ); + } + + public void expect( final String testUrl, final int responseCode, final InputStream bodyStream ) + throws Exception + { + servlet.expect( "GET", testUrl, responseCode, bodyStream ); + servlet.expect( "HEAD", testUrl, responseCode, (String) null ); + } + + public void expect( final String method, final String testUrl, final int responseCode, final InputStream bodyStream ) + throws Exception + { + servlet.expect( method, testUrl, responseCode, bodyStream ); + } + + public Integer getAccessesFor( final String path ) + { + return servlet.getAccessesFor( path ); + } + + public Integer getAccessesFor( final String method, final String path ) + { + return servlet.getAccessesFor( method, path ); } } From 428cafc606bc0e812ef280d8683935c3b5b404cf Mon Sep 17 00:00:00 2001 From: John Casey Date: Tue, 19 May 2015 17:09:51 -0500 Subject: [PATCH 2/2] Make deployment conditional on whether it's a PR build. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 61f0ad897..9168e80a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,4 +9,5 @@ cache: - '$HOME/.m2/repository' install: /bin/true -script: mvn deploy -s ./travis-settings.xml -V -Prun-its -q -B -e \ No newline at end of file +script: + - '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && mvn -s ./travis-settings.xml -Prun-its -q -B -e install || mvn deploy -s ./travis-settings.xml -V -Prun-its -q -B -e' \ No newline at end of file