MNG-5795: Verify that core extensions can be retrieved when a mirror is used that requires basic auth.
Project: http://git-wip-us.apache.org/repos/asf/maven-integration-testing/repo Commit: http://git-wip-us.apache.org/repos/asf/maven-integration-testing/commit/bae4c23a Tree: http://git-wip-us.apache.org/repos/asf/maven-integration-testing/tree/bae4c23a Diff: http://git-wip-us.apache.org/repos/asf/maven-integration-testing/diff/bae4c23a Branch: refs/heads/master Commit: bae4c23a4b85e1c187529c46fb58d87d9bf1a553 Parents: bc177b6 Author: Jason van Zyl <ja...@tesla.io> Authored: Thu Apr 2 00:18:55 2015 -0400 Committer: Jason van Zyl <ja...@tesla.io> Committed: Thu Apr 2 00:20:19 2015 -0400 ---------------------------------------------------------------------- core-it-suite/pom.xml | 204 +++++++++++-------- .../java/org/apache/maven/it/HttpServer.java | 199 ++++++++++++++++++ .../it/MavenITmng5771CoreExtensionsTest.java | 31 +++ .../settings-template-mirror-auth.xml | 41 ++++ pom.xml | 2 + 5 files changed, 387 insertions(+), 90 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/maven-integration-testing/blob/bae4c23a/core-it-suite/pom.xml ---------------------------------------------------------------------- diff --git a/core-it-suite/pom.xml b/core-it-suite/pom.xml index 6b1050b..2a41415 100644 --- a/core-it-suite/pom.xml +++ b/core-it-suite/pom.xml @@ -1,25 +1,18 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you 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 +<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor + license agreements. See the NOTICE file distributed with this work for additional + information regarding copyright ownership. The ASF licenses this file to + you 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. --> - 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. ---> - -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> @@ -33,40 +26,31 @@ under the License. <name>Maven ITs</name> <description>The effective Maven Integration Tests suite.</description> - <!-- - By default, the project just packages the tests in an artifact. To actually run them, activate the profile "run-its": - - mvn clean test -Prun-its - - This will subject the Maven version running the build to the integration tests. If you would like to test a different - Maven distribution, you can use the system property "mavenHome" to specify the path of the Maven distribution to test: - - mvn clean test -Prun-its -DmavenHome=<maven-under-test> - - Alternatively, you can just specify the version of a previously installed/deployed Maven distribution which will be - downloaded, unpacked and tested: - - mvn clean test -Prun-its -DmavenVersion=2.2.1 - - It's also possible to point the ITs at an already downloaded Maven distribution: - - mvn clean test -Prun-its -DmavenDistro=<path-to-bin-archive> - - To run the ITs using embedded Maven 3.x, additionally activate the profile "embedded". - - ITs that don't require to fork Maven can also be run from the IDE using the Maven projects from the workspace if the - Maven dependencies are added to the test class path. - - If you're behind a proxy, use the system properties proxy.host, proxy.port, proxy.user and proxy.pass to specify the - required proxy setup for the ITs. Alternatively, set the system property maven.it.central to a URL of a local - repository manager that proxies the required artifacts. - --> + <!-- By default, the project just packages the tests in an artifact. To + actually run them, activate the profile "run-its": mvn clean test -Prun-its + This will subject the Maven version running the build to the integration + tests. If you would like to test a different Maven distribution, you can + use the system property "mavenHome" to specify the path of the Maven distribution + to test: mvn clean test -Prun-its -DmavenHome=<maven-under-test> Alternatively, + you can just specify the version of a previously installed/deployed Maven + distribution which will be downloaded, unpacked and tested: mvn clean test + -Prun-its -DmavenVersion=2.2.1 It's also possible to point the ITs at an + already downloaded Maven distribution: mvn clean test -Prun-its -DmavenDistro=<path-to-bin-archive> + To run the ITs using embedded Maven 3.x, additionally activate the profile + "embedded". ITs that don't require to fork Maven can also be run from the + IDE using the Maven projects from the workspace if the Maven dependencies + are added to the test class path. If you're behind a proxy, use the system + properties proxy.host, proxy.port, proxy.user and proxy.pass to specify the + required proxy setup for the ITs. Alternatively, set the system property + maven.it.central to a URL of a local repository manager that proxies the + required artifacts. --> <properties> <surefireMemory>-Xmx384m -XX:MaxPermSize=192m</surefireMemory> <!-- The original Maven distribution to test. --> <mavenHome>${maven.home}</mavenHome> - <!-- The (possibly instrumented copy of the) Maven distribution we actually use for the tests. --> + <!-- The (possibly instrumented copy of the) Maven distribution we actually + use for the tests. --> <preparedMavenHome>${mavenHome}</preparedMavenHome> <!-- default properties used to filter the global settings --> <maven.it.central>http://repo1.maven.org/maven2</maven.it.central> @@ -77,6 +61,7 @@ under the License. <proxy.user></proxy.user> <proxy.pass></proxy.pass> <slf4jVersion>1.6.1</slf4jVersion> + <jetty9Version>9.0.4.v20130625</jetty9Version> </properties> <dependencies> @@ -85,7 +70,7 @@ under the License. <artifactId>junit</artifactId> <version>4.8.2</version> <!-- NOTE: Use compile scope for transitivity. --> - </dependency> + </dependency> <dependency> <groupId>org.codehaus.plexus</groupId> <artifactId>plexus-utils</artifactId> @@ -96,34 +81,63 @@ under the License. <groupId>org.apache.maven.its</groupId> <artifactId>maven-it-helper</artifactId> <version>2.1-SNAPSHOT</version> -<!-- TODO: not transitive in tests artifact, so must be left in main scope - <scope>test</scope> ---> + <!-- TODO: not transitive in tests artifact, so must be left in main + scope <scope>test</scope> --> </dependency> <dependency> <groupId>org.apache.maven.shared</groupId> <artifactId>maven-verifier</artifactId> -<!-- TODO: not transitive in tests artifact, so must be left in main scope - <scope>test</scope> ---> + <!-- TODO: not transitive in tests artifact, so must be left in main + scope <scope>test</scope> --> </dependency> - <!-- - Should be fine to introduce this here, even if we use the embedder as it should be using an isolated classloader - Used to simplify tests that provide a test HTTP server. - --> + <!-- Should be fine to introduce this here, even if we use the embedder + as it should be using an isolated classloader Used to simplify tests that + provide a test HTTP server. --> <dependency> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty</artifactId> <version>6.1.14</version> -<!-- TODO: not transitive in tests artifact, so must be left in main scope - <scope>test</scope> ---> + <!-- TODO: not transitive in tests artifact, so must be left in main + scope <scope>test</scope> --> + <exclusions> + <exclusion> + <artifactId>servlet-api-2.5</artifactId> + <groupId>org.mortbay.jetty</groupId> + </exclusion> + </exclusions> </dependency> <dependency> <groupId>org.apache.maven.shared</groupId> <artifactId>maven-shared-utils</artifactId> <version>0.6</version> - </dependency> + </dependency> + + <!-- Jetty9 server for testing --> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>${jetty9Version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-security</artifactId> + <version>${jetty9Version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>${jetty9Version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.orbit</groupId> + <artifactId>javax.servlet</artifactId> + <version>3.0.0.v201112011016</version> + </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <version>16.0</version> + </dependency> </dependencies> <build> @@ -178,19 +192,19 @@ under the License. <profiles> <profile> - <id>parallel</id> - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <configuration> - <parallel>classes</parallel> - <threadCount>6</threadCount> - </configuration> - </plugin> - </plugins> - </build> + <id>parallel</id> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <parallel>classes</parallel> + <threadCount>6</threadCount> + </configuration> + </plugin> + </plugins> + </build> </profile> <profile> <id>run-its</id> @@ -241,7 +255,8 @@ under the License. <configuration> <systemProperties combine.children="append"> <property> - <!-- Pass this through to the tests (if set!) to have them pick the right repository --> + <!-- Pass this through to the tests (if set!) to have them + pick the right repository --> <name>maven.repo.local</name> <value>${maven.repo.local}</value> </property> @@ -265,7 +280,8 @@ under the License. <configuration> <systemProperties combine.children="append"> <property> - <!-- Pass this through to the tests (if set!) to have them pick the right repository layout --> + <!-- Pass this through to the tests (if set!) to have them + pick the right repository layout --> <name>maven.repo.local.layout</name> <value>${maven.repo.local.layout}</value> </property> @@ -284,8 +300,10 @@ under the License. <configuration> <skip>false</skip> <forkMode>once</forkMode> - <argLine>${surefireMemory} -Dcom.sun.management.jmxremote=true</argLine> - <!-- NOTE: Maven plugins have access to the system class path so keep it clean --> + <argLine>${surefireMemory} + -Dcom.sun.management.jmxremote=true</argLine> + <!-- NOTE: Maven plugins have access to the system class path + so keep it clean --> <useSystemClassLoader>false</useSystemClassLoader> <systemProperties combine.children="append"> <property> @@ -360,11 +378,14 @@ under the License. </goals> <configuration> <tasks> - <delete dir="${mavenHome}"/> - <unzip src="${project.build.directory}/maven-bin.zip" dest="${mavenHome}"> - <globmapper from="apache-maven-${mavenVersion}/*" to="*" handledirsep="true" /> + <delete dir="${mavenHome}" /> + <unzip src="${project.build.directory}/maven-bin.zip" + dest="${mavenHome}"> + <globmapper from="apache-maven-${mavenVersion}/*" + to="*" handledirsep="true" /> </unzip> - <chmod dir="${mavenHome}/bin" perm="ugo+rx" includes="mvn,mvnDebug"/> + <chmod dir="${mavenHome}/bin" perm="ugo+rx" + includes="mvn,mvnDebug" /> </tasks> </configuration> </execution> @@ -404,11 +425,13 @@ under the License. </goals> <configuration> <tasks> - <delete dir="${mavenHome}"/> + <delete dir="${mavenHome}" /> <unzip src="${mavenDistro}" dest="${mavenHome}"> - <regexpmapper from="^([^/]+)/(.*)$" to="\2" handledirsep="true" /> + <regexpmapper from="^([^/]+)/(.*)$" + to="\2" handledirsep="true" /> </unzip> - <chmod dir="${mavenHome}/bin" perm="ugo+rx" includes="mvn,mvnDebug"/> + <chmod dir="${mavenHome}/bin" perm="ugo+rx" + includes="mvn,mvnDebug" /> </tasks> </configuration> </execution> @@ -444,11 +467,12 @@ under the License. </goals> <configuration> <tasks> - <delete dir="${preparedMavenHome}"/> + <delete dir="${preparedMavenHome}" /> <copy todir="${preparedMavenHome}" overwrite="true"> - <fileset dir="${mavenHome}"/> + <fileset dir="${mavenHome}" /> </copy> - <chmod dir="${preparedMavenHome}/bin" perm="ugo+rx" includes="mvn,mvnDebug"/> + <chmod dir="${preparedMavenHome}/bin" perm="ugo+rx" + includes="mvn,mvnDebug" /> </tasks> </configuration> </execution> http://git-wip-us.apache.org/repos/asf/maven-integration-testing/blob/bae4c23a/core-it-suite/src/test/java/org/apache/maven/it/HttpServer.java ---------------------------------------------------------------------- diff --git a/core-it-suite/src/test/java/org/apache/maven/it/HttpServer.java b/core-it-suite/src/test/java/org/apache/maven/it/HttpServer.java new file mode 100644 index 0000000..e94780a --- /dev/null +++ b/core-it-suite/src/test/java/org/apache/maven/it/HttpServer.java @@ -0,0 +1,199 @@ +package org.apache.maven.it; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.util.Collections; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.security.HashLoginService; +import org.eclipse.jetty.security.authentication.BasicAuthenticator; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.util.security.Constraint; +import org.eclipse.jetty.util.security.Password; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; + +import com.google.common.io.ByteStreams; +import com.google.common.io.Closer; + +/** + * An HTTP server that handles all requests on a given port from a specified source, optionally secured using BASIC auth by providing a username and password. + * + * The source can either be a URL or a directory. When a request is made the request is satisfied from the provided source. + * + * @author Jason van Zyl + * + */ +public class HttpServer { + + private final Server server; + private final StreamSource source; + private final String username; + private final String password; + + public HttpServer(int port, String username, String password, StreamSource source) { + this.username = username; + this.password = password; + this.source = source; + this.server = server(port); + } + + public void start() throws Exception { + server.start(); + //server.join(); + } + + public void stop() throws Exception { + server.stop(); + } + + public int port() { + return ((ServerConnector) server.getConnectors()[0]).getLocalPort(); + } + + private Server server(int port) { + + QueuedThreadPool threadPool = new QueuedThreadPool(); + threadPool.setMaxThreads(500); + Server server = new Server(threadPool); + server.addBean(new ScheduledExecutorScheduler()); + + ServerConnector http = new ServerConnector(server); + http.setPort(port); + http.setIdleTimeout(30000); + server.addConnector(http); + + StreamSourceHandler handler = new StreamSourceHandler(source); + + if (username != null && password != null) { + HashLoginService loginService = new HashLoginService("Test Server"); + loginService.putUser(username, new Password(password), new String[] { + "user" + }); + server.addBean(loginService); + + ConstraintSecurityHandler security = new ConstraintSecurityHandler(); + server.setHandler(security); + + Constraint constraint = new Constraint(); + constraint.setName("auth"); + constraint.setAuthenticate(true); + constraint.setRoles(new String[] { + "user", "admin" + }); + + ConstraintMapping mapping = new ConstraintMapping(); + mapping.setPathSpec("/*"); + mapping.setConstraint(constraint); + + security.setConstraintMappings(Collections.singletonList(mapping)); + security.setAuthenticator(new BasicAuthenticator()); + security.setLoginService(loginService); + security.setHandler(handler); + } else { + server.setHandler(handler); + } + return server; + } + + public static HttpServerBuilder builder() { + return new HttpServerBuilder(); + } + + public static class HttpServerBuilder { + + private int port; + private String username; + private String password; + private StreamSource source; + + public HttpServerBuilder port(int port) { + this.port = port; + return this; + } + + public HttpServerBuilder username(String username) { + this.username = username; + return this; + } + + public HttpServerBuilder password(String password) { + this.password = password; + return this; + } + + public HttpServerBuilder source(final String source) { + this.source = new StreamSource() { + public InputStream stream(String path) throws IOException { + return new URL(String.format("%s/%s", source, path)).openStream(); + } + }; + return this; + } + + public HttpServerBuilder source(final File source) { + this.source = new StreamSource() { + public InputStream stream(String path) throws IOException { + return new FileInputStream(new File(source, path)); + } + }; + return this; + } + + public HttpServer build() { + return new HttpServer(port, username, password, source); + } + } + + public static interface StreamSource { + InputStream stream(String path) throws IOException; + } + + public static class StreamSourceHandler extends AbstractHandler { + + private final StreamSource source; + + public StreamSourceHandler(StreamSource source) { + this.source = source; + } + + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + response.setContentType("application/octet-stream"); + response.setStatus(HttpServletResponse.SC_OK); + Closer closer = Closer.create(); + try { + // /target --> target + InputStream in = closer.register(source.stream(target.substring(1))); + OutputStream out = closer.register(response.getOutputStream()); + ByteStreams.copy(in, out); + } catch (Throwable e) { + throw closer.rethrow(e); + } finally { + closer.close(); + } + baseRequest.setHandled(true); + } + } + + public static void main(String[] args) throws Exception { + HttpServer server = HttpServer.builder() // + .port(0) // + .username("maven") // + .password("secret") // + .source(new File("/tmp/repo")) // + .build(); + server.start(); + } +} http://git-wip-us.apache.org/repos/asf/maven-integration-testing/blob/bae4c23a/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng5771CoreExtensionsTest.java ---------------------------------------------------------------------- diff --git a/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng5771CoreExtensionsTest.java b/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng5771CoreExtensionsTest.java index 29f0119..41dad74 100644 --- a/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng5771CoreExtensionsTest.java +++ b/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng5771CoreExtensionsTest.java @@ -1,6 +1,7 @@ package org.apache.maven.it; import java.io.File; +import java.util.Properties; import org.apache.maven.it.util.ResourceExtractor; @@ -30,6 +31,36 @@ public class MavenITmng5771CoreExtensionsTest verifier.resetStreams(); } + public void testCoreExtensionRetrievedFromAMirrorWithBasicAuthentication() + throws Exception + { + File testDir = ResourceExtractor.simpleExtractResources( getClass(), "/mng-5771-core-extensions" ); + + HttpServer server = HttpServer.builder() // + .port(0) // + .username("maven") // + .password("secret") // + .source(new File(testDir, "repo")) // + .build(); + server.start(); + + Verifier verifier = newVerifier( testDir.getAbsolutePath() ); + Properties properties = verifier.newDefaultFilterProperties(); + properties.setProperty("@port@", Integer.toString(server.port())); + verifier.filterFile( "settings-template-mirror-auth.xml", "settings.xml", "UTF-8", properties ); + + verifier = newVerifier( new File( testDir, "client" ).getAbsolutePath() ); + verifier.deleteDirectory( "target" ); + verifier.deleteArtifacts( "org.apache.maven.its.it-core-extensions" ); + verifier.getCliOptions().add( "-s" ); + verifier.getCliOptions().add( new File( testDir, "settings.xml" ).getAbsolutePath() ); + verifier.executeGoal( "validate" ); + verifier.verifyErrorFreeLog(); + verifier.resetStreams(); + + server.stop(); + } + public void testCoreExtensionNoDescriptor() throws Exception { http://git-wip-us.apache.org/repos/asf/maven-integration-testing/blob/bae4c23a/core-it-suite/src/test/resources/mng-5771-core-extensions/settings-template-mirror-auth.xml ---------------------------------------------------------------------- diff --git a/core-it-suite/src/test/resources/mng-5771-core-extensions/settings-template-mirror-auth.xml b/core-it-suite/src/test/resources/mng-5771-core-extensions/settings-template-mirror-auth.xml new file mode 100644 index 0000000..60b8305 --- /dev/null +++ b/core-it-suite/src/test/resources/mng-5771-core-extensions/settings-template-mirror-auth.xml @@ -0,0 +1,41 @@ +<settings> + <servers> + <server> + <id>repoman</id> + <username>maven</username> + <password>secret</password> + </server> + </servers> + + <mirrors> + <mirror> + <id>repoman</id> + <name>Mirror</name> + <url>http://localhost:@port@</url> + <mirrorOf>external:*</mirrorOf> + </mirror> + </mirrors> + + <profiles> + <profile> + <id>development</id> + <repositories> + <repository> + <id>central</id> + <url>http://central</url> + </repository> + </repositories> + <pluginRepositories> + <pluginRepository> + <id>central</id> + <url>http://central</url> + </pluginRepository> + </pluginRepositories> + </profile> + </profiles> + + <activeProfiles> + <activeProfile>development</activeProfile> + </activeProfiles> +</settings> + http://git-wip-us.apache.org/repos/asf/maven-integration-testing/blob/bae4c23a/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 9d8f3fa..a5b83ed 100644 --- a/pom.xml +++ b/pom.xml @@ -63,6 +63,8 @@ under the License. <maven.site.path>core-its</maven.site.path> <maven.site.cache>${user.home}/maven-sites</maven.site.cache> <rat.ignoreErrors>true</rat.ignoreErrors> + <maven.compiler.source>1.7</maven.compiler.source> + <maven.compiler.target>1.7</maven.compiler.target> </properties> <modules>