summaryrefslogtreecommitdiffstats
path: root/maven-plugins/tags
diff options
context:
space:
mode:
authorantelder <antelder@13f79535-47bb-0310-9956-ffa450edef68>2009-10-28 08:55:19 +0000
committerantelder <antelder@13f79535-47bb-0310-9956-ffa450edef68>2009-10-28 08:55:19 +0000
commitf2edf2d0a50911244d776cf48bce95439333cc3c (patch)
tree138d4b4eade67f914dc495521ffc344ff7430fb8 /maven-plugins/tags
parent814c08b910d1517597d522be9b10df9f24344519 (diff)
[maven-release-plugin] copy for tag maven-osgi-junit-plugin-1.0
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@830470 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'maven-plugins/tags')
-rw-r--r--maven-plugins/tags/maven-osgi-junit-plugin-1.0/LICENSE205
-rw-r--r--maven-plugins/tags/maven-osgi-junit-plugin-1.0/NOTICE6
-rw-r--r--maven-plugins/tags/maven-osgi-junit-plugin-1.0/README67
-rw-r--r--maven-plugins/tags/maven-osgi-junit-plugin-1.0/RELEASE_NOTES4
-rw-r--r--maven-plugins/tags/maven-osgi-junit-plugin-1.0/pom.xml302
-rw-r--r--maven-plugins/tags/maven-osgi-junit-plugin-1.0/src/main/java/org/apache/tuscany/maven/plugin/surefire/ForkConfiguration.java239
-rw-r--r--maven-plugins/tags/maven-osgi-junit-plugin-1.0/src/main/java/org/apache/tuscany/maven/plugin/surefire/OSGiSurefireBooter.java1018
-rw-r--r--maven-plugins/tags/maven-osgi-junit-plugin-1.0/src/main/java/org/apache/tuscany/maven/plugin/surefire/OSGiSurefirePlugin.java1310
8 files changed, 3151 insertions, 0 deletions
diff --git a/maven-plugins/tags/maven-osgi-junit-plugin-1.0/LICENSE b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/LICENSE
new file mode 100644
index 0000000000..6e529a25c4
--- /dev/null
+++ b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/LICENSE
@@ -0,0 +1,205 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
+
+
+
diff --git a/maven-plugins/tags/maven-osgi-junit-plugin-1.0/NOTICE b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/NOTICE
new file mode 100644
index 0000000000..12c7095949
--- /dev/null
+++ b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/NOTICE
@@ -0,0 +1,6 @@
+Apache Tuscany Maven OSGi JUnit Plugin
+Copyright (c) 2005 - 2009 The Apache Software Foundation
+
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+
diff --git a/maven-plugins/tags/maven-osgi-junit-plugin-1.0/README b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/README
new file mode 100644
index 0000000000..9466d5f8cd
--- /dev/null
+++ b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/README
@@ -0,0 +1,67 @@
+A Maven plugin used by the Tuscany SCA project for OSGi JUnit testing.
+Not exactly clear what its does, there's some discusssion about it at:
+http://apache.markmail.org/message/uxt7afrquwc75qxj
+
+To build, from the top maven-bundle-plugin run maven:
+
+mvn
+
+or once all the dependencies have been downloaded and a succesful build run use:
+
+mvn clean install -o
+
+So as to avoid the Tuscany SCA project using SNAPSHOT dependencies any changes
+to this module should be released and the Tuscany SCA project updated to use
+the newly released version.
+
+To release this module:
+
+mvn release:prepare
+
+followed by:
+
+mvn release:perform
+
+That will automatically create an SVN tag from the release, update the version
+numbers in the pom.xml files in the trunk and tag, and deploy the artifacts to the
+staging repository defined by the <deploy.altRepository> in your Maven settings.xml.
+While running it will prompt you for the names for the tag, release version etc.
+
+In your maven settings.xml file you must have a server defined named "apache.releases",
+and a profile named "release". For example:
+
+ <servers>
+ ...
+ <server>
+ <id>apache.releases</id>
+ <username>antelder</username>
+ <privateKey>\ant\id_dsa</privateKey>
+ <passphrase>xxx</passphrase>
+ <directoryPermissions>775</directoryPermissions>
+ <filePermissions>664</filePermissions>
+ </server>
+ </servers>
+
+ <profiles>
+ ...
+ <profile>
+ <id>release</id>
+ <properties>
+ <gpg.passphrase>...</gpg.passphrase>
+ <deploy.altRepository>apache.releases::default::scp://people.apache.org/home/antelder/public_html/tuscany/maven-osgi-junit-plugin-1.0</deploy.altRepository>
+ </properties>
+ </profile>
+ </profiles>
+
+Call a vote to release the module, eg: http://apache.markmail.org/message/6jnlfxbx7uklt5nv
+
+After a successful vote copy the staging artifacts to the live repository, eg:
+
+cp -p -v -R maven-bundle-plugin-1.0/org/apache/tuscany/maven/plugins/ /x1/www/people.apache.org/repo/m2-ibiblio-rsync-repository/org/apache/tuscany/maven/plugins
+
+
+
+
+
+
+
diff --git a/maven-plugins/tags/maven-osgi-junit-plugin-1.0/RELEASE_NOTES b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/RELEASE_NOTES
new file mode 100644
index 0000000000..deb1a5b46c
--- /dev/null
+++ b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/RELEASE_NOTES
@@ -0,0 +1,4 @@
+Apache Tuscany Maven OSGi JUNit Plugin 1.0 Release Notes
+========================================================
+
+Initial release
diff --git a/maven-plugins/tags/maven-osgi-junit-plugin-1.0/pom.xml b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/pom.xml
new file mode 100644
index 0000000000..7354c05d48
--- /dev/null
+++ b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/pom.xml
@@ -0,0 +1,302 @@
+<?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
+ *
+ * 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/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache</groupId>
+ <artifactId>apache</artifactId>
+ <version>4</version>
+ </parent>
+
+ <groupId>org.apache.tuscany.maven.plugins</groupId>
+ <artifactId>maven-osgi-junit-plugin</artifactId>
+ <packaging>maven-plugin</packaging>
+ <name>Apache Tuscany OSGi JUnit Maven Plugin</name>
+ <version>1.0</version>
+
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/tuscany/maven-plugins/tags/maven-osgi-junit-plugin-1.0</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/tuscany/maven-plugins/tags/maven-osgi-junit-plugin-1.0</developerConnection>
+ <url>scm:svn:https://svn.apache.org/repos/asf/tuscany/maven-plugins/tags/maven-osgi-junit-plugin-1.0</url>
+ </scm>
+
+ <distributionManagement>
+ <repository>
+ <id>apache.releases</id>
+ <name>Apache Release Distribution Repository</name>
+ <url>scp://people.apache.org/www/people.apache.org/repo/m2-ibiblio-rsync-repository</url>
+ </repository>
+ <snapshotRepository>
+ <id>apache.snapshots</id>
+ <name>Apache Development Snapshot Repository</name>
+ <url>scp://people.apache.org/www/people.apache.org/repo/m2-snapshot-repository</url>
+ <uniqueVersion>false</uniqueVersion>
+ </snapshotRepository>
+ </distributionManagement>
+
+ <repositories>
+ <!-- Apache SNAPSHOT repository for unreleased artifacts -->
+ <repository>
+ <id>apache.snapshots</id>
+ <name>Apache SNAPSHOT Repository</name>
+ <url>http://people.apache.org/repo/m2-snapshot-repository</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ <!-- Tuscany repository to hold artifacts that are not published in the public maven repos -->
+ <repository>
+ <id>tuscany.repo</id>
+ <name>Tuscany Maven 2.x Repository</name>
+ <url>http://svn.apache.org/repos/asf/tuscany/maven</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+
+ <pluginRepositories>
+ <!-- Apache repository for artifacts released by Apache TLP projects -->
+ <pluginRepository>
+ <id>apache</id>
+ <name>Apache Repository</name>
+ <url>http://people.apache.org/repo/m2-ibiblio-rsync-repository</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </pluginRepository>
+
+ <!-- Apache SNAPSHOT repository for unreleased artifacts -->
+ <pluginRepository>
+ <id>apache.snapshots</id>
+ <name>Apache SNAPSHOT Repository</name>
+ <url>http://people.apache.org/repo/m2-snapshot-repository</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </pluginRepository>
+
+ </pluginRepositories>
+
+ <profiles>
+ <profile>
+ <id>release</id>
+ <build>
+ <plugins>
+
+ <plugin>
+ <inherited>true</inherited>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <version>2.4</version>
+ <configuration>
+ <altDeploymentRepository>${deploy.altRepository}</altDeploymentRepository>
+ <updateReleaseInfo>true</updateReleaseInfo>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.0-alpha-4</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>deploy</id>
+ <build>
+ <defaultGoal>deploy</defaultGoal>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>2.0.4</version>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>2.0.8</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-project</artifactId>
+ <version>2.0.8</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.maven.surefire</groupId>
+ <artifactId>surefire-booter</artifactId>
+ <version>2.4.3</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-core</artifactId>
+ <version>2.0.8</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-toolchain</artifactId>
+ <version>1.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.tuscany.sca</groupId>
+ <artifactId>tuscany-node-launcher-equinox</artifactId>
+ <version>2.0-M3</version>
+ <scope>runtime</scope>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse</groupId>
+ <artifactId>osgi</artifactId>
+ <version>3.5.0-v20090520</version>
+ <scope>compile</scope>
+ </dependency>
+
+
+ </dependencies>
+
+ <build>
+ <defaultGoal>install</defaultGoal>
+
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ <resource>
+ <directory>.</directory>
+ <targetPath>META-INF</targetPath>
+ <filtering>true</filtering>
+ <includes>
+ <include>LICENSE</include>
+ <include>NOTICE</include>
+ </includes>
+ </resource>
+ </resources>
+
+ <pluginManagement>
+
+ <plugins>
+ <!-- compiler plugin configuration -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.0.2</version>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+
+ <!-- jar plugin configuration -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.1</version>
+ <configuration>
+ <archive>
+ <manifestEntries>
+ <Extension-Name>${project.artifactId}</Extension-Name>
+ <Specification-Title>${name}</Specification-Title>
+ <Specification-Vendor>The Apache Software Foundation</Specification-Vendor>
+ <Specification-Version>${version}</Specification-Version>
+ <Implementation-Title>${name}</Implementation-Title>
+ <Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
+ <Implementation-Vendor>The Apache Software Foundation</Implementation-Vendor>
+ <Implementation-Version>${version}</Implementation-Version>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ </plugin>
+
+ <!-- surefire plugin configuration -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.4.3</version>
+ <configuration>
+ <includes>
+ <include>**/*TestCase.java</include>
+ </includes>
+ <reportFormat>brief</reportFormat>
+ <useFile>false</useFile>
+ <forkMode>once</forkMode>
+ <argLine>-ea -Xmx256m</argLine>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <configuration>
+ <tagBase>https://svn.apache.org/repos/asf/tuscany/maven-plugins/tags</tagBase>
+ <useReleaseProfile>false</useReleaseProfile>
+ <preparationGoals>clean install</preparationGoals>
+ <goals>deploy</goals>
+ <arguments>-Prelease,deploy</arguments>
+ <autoVersionSubmodules>true</autoVersionSubmodules>
+ </configuration>
+ </plugin>
+
+ </plugins>
+
+ </pluginManagement>
+
+ </build>
+
+</project>
diff --git a/maven-plugins/tags/maven-osgi-junit-plugin-1.0/src/main/java/org/apache/tuscany/maven/plugin/surefire/ForkConfiguration.java b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/src/main/java/org/apache/tuscany/maven/plugin/surefire/ForkConfiguration.java
new file mode 100644
index 0000000000..eb391970ca
--- /dev/null
+++ b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/src/main/java/org/apache/tuscany/maven/plugin/surefire/ForkConfiguration.java
@@ -0,0 +1,239 @@
+package org.apache.tuscany.maven.plugin.surefire;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import org.apache.maven.surefire.booter.SurefireBooterForkException;
+import org.apache.maven.surefire.booter.shade.org.codehaus.plexus.util.cli.Commandline;
+import org.apache.maven.surefire.util.UrlUtils;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * Derived from surefire-booter 2.4.3
+ * Configuration for forking tests.
+ *
+ */
+@SuppressWarnings("unchecked")
+public class ForkConfiguration {
+ public static final String FORK_ONCE = "once";
+
+ public static final String FORK_ALWAYS = "always";
+
+ public static final String FORK_NEVER = "never";
+
+ private String forkMode;
+
+ private boolean useSystemClassLoader;
+ private boolean useManifestOnlyJar;
+
+ private Properties systemProperties;
+
+ private String jvmExecutable;
+
+ private String argLine;
+
+ private Map environmentVariables;
+
+ private File workingDirectory;
+
+ private boolean debug;
+
+ private String debugLine;
+
+ public void setForkMode(String forkMode) {
+ if ("pertest".equalsIgnoreCase(forkMode)) {
+ this.forkMode = FORK_ALWAYS;
+ } else if ("none".equalsIgnoreCase(forkMode)) {
+ this.forkMode = FORK_NEVER;
+ } else if (forkMode.equals(FORK_NEVER) || forkMode.equals(FORK_ONCE) || forkMode.equals(FORK_ALWAYS)) {
+ this.forkMode = forkMode;
+ } else {
+ throw new IllegalArgumentException("Fork mode " + forkMode + " is not a legal value");
+ }
+ }
+
+ public boolean isForking() {
+ return !FORK_NEVER.equals(forkMode);
+ }
+
+ public void setUseSystemClassLoader(boolean useSystemClassLoader) {
+ this.useSystemClassLoader = useSystemClassLoader;
+ }
+
+ public boolean isUseSystemClassLoader() {
+ return useSystemClassLoader;
+ }
+
+ public void setSystemProperties(Properties systemProperties) {
+ this.systemProperties = (Properties)systemProperties.clone();
+ }
+
+ public void setJvmExecutable(String jvmExecutable) {
+ this.jvmExecutable = jvmExecutable;
+ }
+
+ public void setArgLine(String argLine) {
+ this.argLine = argLine;
+ }
+
+ public void setDebugLine(String debugLine) {
+ this.debugLine = debugLine;
+ }
+
+ public void setEnvironmentVariables(Map environmentVariables) {
+ this.environmentVariables = new HashMap(environmentVariables);
+ }
+
+ public void setWorkingDirectory(File workingDirectory) {
+ this.workingDirectory = workingDirectory;
+ }
+
+ public String getForkMode() {
+ return forkMode;
+ }
+
+ public Properties getSystemProperties() {
+ return systemProperties;
+ }
+
+ /**
+ * @throws SurefireBooterForkException
+ * @deprecated use the 2-arg alternative.
+ */
+ public Commandline createCommandLine(List classPath) throws SurefireBooterForkException {
+ return createCommandLine(classPath, false);
+ }
+
+ public Commandline createCommandLine(List classPath, boolean useJar) throws SurefireBooterForkException {
+ Commandline cli = new Commandline();
+
+ cli.setExecutable(jvmExecutable);
+
+ if (argLine != null) {
+ cli.createArg().setLine(argLine);
+ }
+
+ if (environmentVariables != null) {
+ Iterator iter = environmentVariables.keySet().iterator();
+
+ while (iter.hasNext()) {
+ String key = (String)iter.next();
+
+ String value = (String)environmentVariables.get(key);
+
+ cli.addEnvironment(key, value);
+ }
+ }
+
+ if (debugLine != null && !"".equals(debugLine)) {
+ cli.createArg().setLine(debugLine);
+ }
+
+ if (useJar) {
+ File jarFile;
+ try {
+ jarFile = createJar(classPath);
+ } catch (IOException e) {
+ throw new SurefireBooterForkException("Error creating archive file", e);
+ }
+
+ cli.createArg().setValue("-jar");
+
+ cli.createArg().setValue(jarFile.getAbsolutePath());
+ } else {
+ cli.createArg().setValue("-classpath");
+
+ cli.createArg().setValue(StringUtils.join(classPath.iterator(), File.pathSeparator));
+
+ cli.createArg().setValue(OSGiSurefireBooter.class.getName());
+ }
+
+ cli.setWorkingDirectory(workingDirectory.getAbsolutePath());
+
+ return cli;
+ }
+
+ /**
+ * Create a jar with just a manifest containing a Main-Class entry for SurefireBooter and a Class-Path entry
+ * for all classpath elements.
+ *
+ * @param classPath List&lt;String> of all classpath elements.
+ * @return
+ * @throws IOException
+ */
+ private File createJar(List classPath) throws IOException {
+ File file = File.createTempFile("surefirebooter", ".jar");
+ if (!debug) {
+ file.deleteOnExit();
+ }
+ FileOutputStream fos = new FileOutputStream(file);
+ JarOutputStream jos = new JarOutputStream(fos);
+ jos.setLevel(JarOutputStream.STORED);
+ JarEntry je = new JarEntry("META-INF/MANIFEST.MF");
+ jos.putNextEntry(je);
+
+ Manifest man = new Manifest();
+
+ // we can't use StringUtils.join here since we need to add a '/' to
+ // the end of directory entries - otherwise the jvm will ignore them.
+ String cp = "";
+ for (Iterator it = classPath.iterator(); it.hasNext();) {
+ String el = (String)it.next();
+ // NOTE: if File points to a directory, this entry MUST end in '/'.
+ cp += UrlUtils.getURL(new File(el)).toExternalForm() + " ";
+ }
+
+ man.getMainAttributes().putValue("Manifest-Version", "1.0");
+ man.getMainAttributes().putValue("Class-Path", cp.trim());
+ man.getMainAttributes().putValue("Main-Class", OSGiSurefireBooter.class.getName());
+
+ man.write(jos);
+ jos.close();
+
+ return file;
+ }
+
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ public boolean isDebug() {
+ return debug;
+ }
+
+ public void setUseManifestOnlyJar(boolean useManifestOnlyJar) {
+ this.useManifestOnlyJar = useManifestOnlyJar;
+ }
+
+ public boolean isUseManifestOnlyJar() {
+ return useManifestOnlyJar;
+ }
+}
diff --git a/maven-plugins/tags/maven-osgi-junit-plugin-1.0/src/main/java/org/apache/tuscany/maven/plugin/surefire/OSGiSurefireBooter.java b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/src/main/java/org/apache/tuscany/maven/plugin/surefire/OSGiSurefireBooter.java
new file mode 100644
index 0000000000..e59c432f69
--- /dev/null
+++ b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/src/main/java/org/apache/tuscany/maven/plugin/surefire/OSGiSurefireBooter.java
@@ -0,0 +1,1018 @@
+package org.apache.tuscany.maven.plugin.surefire;
+
+/*
+ * 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.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.maven.surefire.Surefire;
+import org.apache.maven.surefire.booter.SurefireBooterForkException;
+import org.apache.maven.surefire.booter.SurefireExecutionException;
+import org.apache.maven.surefire.booter.output.FileOutputConsumerProxy;
+import org.apache.maven.surefire.booter.output.ForkingStreamConsumer;
+import org.apache.maven.surefire.booter.output.OutputConsumer;
+import org.apache.maven.surefire.booter.output.StandardOutputConsumer;
+import org.apache.maven.surefire.booter.output.SupressFooterOutputConsumerProxy;
+import org.apache.maven.surefire.booter.output.SupressHeaderOutputConsumerProxy;
+import org.apache.maven.surefire.booter.shade.org.codehaus.plexus.util.IOUtil;
+import org.apache.maven.surefire.booter.shade.org.codehaus.plexus.util.StringUtils;
+import org.apache.maven.surefire.booter.shade.org.codehaus.plexus.util.cli.Commandline;
+import org.apache.maven.surefire.booter.shade.org.codehaus.plexus.util.cli.StreamConsumer;
+import org.apache.maven.surefire.testset.TestSetFailedException;
+import org.apache.maven.surefire.util.NestedRuntimeException;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Derived from surefire-booter 2.4.3
+ */
+public class OSGiSurefireBooter {
+ private static final String TEST_SUITE_PROPERTY_PREFIX = "testSuite.";
+ private static final String REPORT_PROPERTY_PREFIX = "report.";
+ private static final String PARAMS_SUFIX = ".params";
+ private static final String TYPES_SUFIX = ".types";
+
+ /**
+ * A classloader that delegates an OSGi bundle
+ */
+ static class BundleClassLoader extends ClassLoader {
+ private Bundle bundle;
+
+ public BundleClassLoader(Bundle bundle, ClassLoader parent) {
+ super(parent);
+ this.bundle = bundle;
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ return bundle.loadClass(name);
+ }
+
+ @Override
+ protected URL findResource(String name) {
+ return bundle.getResource(name);
+ }
+
+ @Override
+ protected Enumeration<URL> findResources(String name) throws IOException {
+ return bundle.getResources(name);
+ }
+
+ }
+
+ private List reports = new ArrayList();
+
+ /**
+ * Test classpath
+ */
+ private List classPathUrls = new ArrayList();
+
+ /**
+ * surefire provider classpath
+ */
+ private List surefireClassPathUrls = new ArrayList();
+
+ /**
+ * surefire boot classpath
+ */
+ private List surefireBootClassPathUrls = new ArrayList();
+
+ private List testSuites = new ArrayList();
+
+ private boolean failIfNoTests = false;
+
+ private int forkedProcessTimeoutInSeconds = 0;
+
+ private boolean redirectTestOutputToFile = false;
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ private ForkConfiguration forkConfiguration;
+
+ public static final int TESTS_SUCCEEDED_EXIT_CODE = 0;
+
+ public static final int TESTS_FAILED_EXIT_CODE = 255;
+
+ public static final int NO_TESTS_EXIT_CODE = 254;
+
+ private static Method assertionStatusMethod;
+
+ /**
+ * @deprecated because the OSGi classloader is really isolated - no parent.
+ */
+ private boolean childDelegation = true;
+
+ private File reportsDirectory;
+
+ /**
+ * This field is set to true if it's running from main. It's used to help decide what classloader to use.
+ */
+ private final boolean isForked;
+
+ /**
+ * Whether to enable assertions or not (can be affected by the fork arguments, and the ability to do so based on the
+ * JVM).
+ */
+ private boolean enableAssertions;
+
+ static {
+ try {
+ assertionStatusMethod =
+ ClassLoader.class.getMethod("setDefaultAssertionStatus", new Class[] {boolean.class});
+ } catch (NoSuchMethodException e) {
+ assertionStatusMethod = null;
+ }
+ }
+
+ public OSGiSurefireBooter() {
+ isForked = false;
+ }
+
+ private OSGiSurefireBooter(boolean isForked) {
+ this.isForked = isForked;
+ }
+
+ // ----------------------------------------------------------------------
+ // Accessors
+ // ----------------------------------------------------------------------
+
+ public void addReport(String report) {
+ addReport(report, null);
+ }
+
+ public void addReport(String report, Object[] constructorParams) {
+ reports.add(new Object[] {report, constructorParams});
+ }
+
+ public void addTestSuite(String suiteClassName, Object[] constructorParams) {
+ testSuites.add(new Object[] {suiteClassName, constructorParams});
+ }
+
+ public void addClassPathUrl(String path) {
+ if (!classPathUrls.contains(path)) {
+ classPathUrls.add(path);
+ }
+ }
+
+ public void addSurefireClassPathUrl(String path) {
+ if (!surefireClassPathUrls.contains(path)) {
+ surefireClassPathUrls.add(path);
+ }
+ }
+
+ public void addSurefireBootClassPathUrl(String path) {
+ if (!surefireBootClassPathUrls.contains(path)) {
+ surefireBootClassPathUrls.add(path);
+ }
+ }
+
+ /**
+ * Setting this to true will cause a failure if there are no tests to run
+ *
+ * @param redirectTestOutputToFile
+ */
+ public void setFailIfNoTests(boolean failIfNoTests) {
+ this.failIfNoTests = failIfNoTests;
+ }
+
+ /**
+ * When forking, setting this to true will make the test output to be saved in a file instead of showing it on the
+ * standard output
+ *
+ * @param redirectTestOutputToFile
+ */
+ public void setRedirectTestOutputToFile(boolean redirectTestOutputToFile) {
+ this.redirectTestOutputToFile = redirectTestOutputToFile;
+ }
+
+ /**
+ * Set the directory where reports will be saved
+ *
+ * @param reportsDirectory the directory
+ */
+ public void setReportsDirectory(File reportsDirectory) {
+ this.reportsDirectory = reportsDirectory;
+ }
+
+ /**
+ * Get the directory where reports will be saved
+ */
+ public File getReportsDirectory() {
+ return reportsDirectory;
+ }
+
+ public void setForkConfiguration(ForkConfiguration forkConfiguration) {
+ this.forkConfiguration = forkConfiguration;
+ }
+
+ public boolean isForking() {
+ return forkConfiguration.isForking();
+ }
+
+ public int run() throws SurefireBooterForkException, SurefireExecutionException {
+ int result;
+
+ if (ForkConfiguration.FORK_NEVER.equals(forkConfiguration.getForkMode())) {
+ result = runSuitesInProcess();
+ } else if (ForkConfiguration.FORK_ONCE.equals(forkConfiguration.getForkMode())) {
+ result = runSuitesForkOnce();
+ } else if (ForkConfiguration.FORK_ALWAYS.equals(forkConfiguration.getForkMode())) {
+ result = runSuitesForkPerTestSet();
+ } else {
+ throw new SurefireExecutionException("Unknown forkmode: " + forkConfiguration.getForkMode(), null);
+ }
+ return result;
+ }
+
+ private int runSuitesInProcess(String testSet, Properties results) throws SurefireExecutionException {
+ if (testSuites.size() != 1) {
+ throw new IllegalArgumentException("Cannot only specify testSet for single test suites");
+ }
+
+ // TODO: replace with plexus
+
+ // noinspection CatchGenericClass,OverlyBroadCatchBlock
+ ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ start();
+ } catch (Exception e1) {
+ throw new SurefireExecutionException(e1.getMessage(), e1);
+ }
+ try {
+ ClassLoader testsClassLoader =
+ useSystemClassLoader() ? ClassLoader.getSystemClassLoader() : createClassLoader(classPathUrls,
+ null,
+ childDelegation);
+
+ // TODO: assertions = true shouldn't be required for this CL if we had proper separation (see TestNG)
+ ClassLoader surefireClassLoader = createClassLoader(surefireClassPathUrls, testsClassLoader);
+
+ Class surefireClass = surefireClassLoader.loadClass(Surefire.class.getName());
+
+ Object surefire = surefireClass.newInstance();
+
+ Method run =
+ surefireClass.getMethod("run", new Class[] {List.class, Object[].class, String.class,
+ ClassLoader.class, ClassLoader.class, Properties.class,
+ Boolean.class});
+
+ Thread.currentThread().setContextClassLoader(testsClassLoader);
+
+ Integer result =
+ (Integer)run.invoke(surefire, new Object[] {reports, testSuites.get(0), testSet, surefireClassLoader,
+ testsClassLoader, results, new Boolean(failIfNoTests)});
+
+ return result.intValue();
+ } catch (InvocationTargetException e) {
+ throw new SurefireExecutionException(e.getTargetException().getMessage(), e.getTargetException());
+ } catch (Exception e) {
+ throw new SurefireExecutionException("Unable to instantiate and execute Surefire", e);
+ } finally {
+ stop();
+ Thread.currentThread().setContextClassLoader(oldContextClassLoader);
+ }
+ }
+
+ private int runSuitesInProcess() throws SurefireExecutionException {
+ // TODO: replace with plexus
+
+ // noinspection CatchGenericClass,OverlyBroadCatchBlock
+ ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
+ try {
+ start();
+ } catch (Exception e1) {
+ throw new SurefireExecutionException(e1.getMessage(), e1);
+ }
+
+ try {
+ // The test classloader must be constructed first to avoid issues with commons-logging until we properly
+ // separate the TestNG classloader
+ ClassLoader testsClassLoader;
+ String testClassPath = getTestClassPathAsString();
+ System.setProperty("surefire.test.class.path", testClassPath);
+ if (useManifestOnlyJar()) {
+ // testsClassLoader = getClass().getClassLoader(); // ClassLoader.getSystemClassLoader()
+ testsClassLoader = createClassLoader(classPathUrls, null, childDelegation);
+ // SUREFIRE-459, trick the app under test into thinking its classpath was conventional (instead of a single manifest-only jar)
+ System.setProperty("surefire.real.class.path", System.getProperty("java.class.path"));
+ System.setProperty("java.class.path", testClassPath);
+ } else {
+ testsClassLoader = createClassLoader(classPathUrls, null, childDelegation);
+ }
+
+ ClassLoader surefireClassLoader = createClassLoader(surefireClassPathUrls, testsClassLoader);
+
+ Class surefireClass = surefireClassLoader.loadClass(Surefire.class.getName());
+
+ Object surefire = surefireClass.newInstance();
+
+ Method run =
+ surefireClass.getMethod("run", new Class[] {List.class, List.class, ClassLoader.class,
+ ClassLoader.class, Boolean.class});
+
+ Thread.currentThread().setContextClassLoader(testsClassLoader);
+
+ Integer result =
+ (Integer)run.invoke(surefire, new Object[] {reports, testSuites, surefireClassLoader, testsClassLoader,
+ new Boolean(failIfNoTests)});
+
+ return result.intValue();
+ } catch (InvocationTargetException e) {
+ throw new SurefireExecutionException(e.getTargetException().getMessage(), e.getTargetException());
+ } catch (Exception e) {
+ throw new SurefireExecutionException("Unable to instantiate and execute Surefire", e);
+ } finally {
+ stop();
+ Thread.currentThread().setContextClassLoader(oldContextClassLoader);
+ }
+ }
+
+ private String getTestClassPathAsString() {
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < classPathUrls.size(); i++) {
+ sb.append(classPathUrls.get(i)).append(File.pathSeparatorChar);
+ }
+ return sb.toString();
+ }
+
+ private int runSuitesForkOnce() throws SurefireBooterForkException {
+ return forkSuites(testSuites, true, true);
+ }
+
+ private int runSuitesForkPerTestSet() throws SurefireBooterForkException {
+ ClassLoader testsClassLoader;
+ ClassLoader surefireClassLoader;
+ try {
+ testsClassLoader = createClassLoader(classPathUrls, null, false);
+ // TODO: assertions = true shouldn't be required if we had proper separation (see TestNG)
+ surefireClassLoader = createClassLoader(surefireClassPathUrls, testsClassLoader, false);
+ } catch (MalformedURLException e) {
+ throw new SurefireBooterForkException("Unable to create classloader to find test suites", e);
+ }
+
+ int globalResult = 0;
+
+ boolean showHeading = true;
+ Properties properties = new Properties();
+ for (Iterator i = testSuites.iterator(); i.hasNext();) {
+ Object[] testSuite = (Object[])i.next();
+
+ Map testSets = getTestSets(testSuite, testsClassLoader, surefireClassLoader);
+
+ for (Iterator j = testSets.keySet().iterator(); j.hasNext();) {
+ Object testSet = j.next();
+ boolean showFooter = !j.hasNext() && !i.hasNext();
+ int result = forkSuite(testSuite, testSet, showHeading, showFooter, properties);
+ if (result > globalResult) {
+ globalResult = result;
+ }
+ showHeading = false;
+ }
+ }
+
+ return globalResult;
+ }
+
+ private Map getTestSets(Object[] testSuite, ClassLoader testsClassLoader, ClassLoader surefireClassLoader)
+ throws SurefireBooterForkException {
+ String className = (String)testSuite[0];
+
+ Object[] params = (Object[])testSuite[1];
+
+ Object suite;
+ try {
+ suite = Surefire.instantiateObject(className, params, surefireClassLoader);
+ } catch (TestSetFailedException e) {
+ throw new SurefireBooterForkException(e.getMessage(), e.getCause());
+ } catch (ClassNotFoundException e) {
+ throw new SurefireBooterForkException("Unable to find class for test suite '" + className + "'", e);
+ } catch (NoSuchMethodException e) {
+ throw new SurefireBooterForkException("Unable to find appropriate constructor for test suite '" + className
+ + "': "
+ + e.getMessage(), e);
+ }
+
+ Map testSets;
+ try {
+ Method m = suite.getClass().getMethod("locateTestSets", new Class[] {ClassLoader.class});
+
+ testSets = (Map)m.invoke(suite, new Object[] {testsClassLoader});
+ } catch (IllegalAccessException e) {
+ throw new SurefireBooterForkException("Error obtaining test sets", e);
+ } catch (NoSuchMethodException e) {
+ throw new SurefireBooterForkException("Error obtaining test sets", e);
+ } catch (InvocationTargetException e) {
+ throw new SurefireBooterForkException(e.getTargetException().getMessage(), e.getTargetException());
+ }
+ return testSets;
+ }
+
+ private int forkSuites(List testSuites, boolean showHeading, boolean showFooter) throws SurefireBooterForkException {
+ Properties properties = new Properties();
+
+ setForkProperties(testSuites, properties);
+
+ return fork(properties, showHeading, showFooter);
+ }
+
+ private int forkSuite(Object[] testSuite,
+ Object testSet,
+ boolean showHeading,
+ boolean showFooter,
+ Properties properties) throws SurefireBooterForkException {
+ setForkProperties(Collections.singletonList(testSuite), properties);
+
+ if (testSet instanceof String) {
+ properties.setProperty("testSet", (String)testSet);
+ }
+
+ return fork(properties, showHeading, showFooter);
+ }
+
+ private void setForkProperties(List testSuites, Properties properties) {
+ addPropertiesForTypeHolder(reports, properties, REPORT_PROPERTY_PREFIX);
+ addPropertiesForTypeHolder(testSuites, properties, TEST_SUITE_PROPERTY_PREFIX);
+
+ for (int i = 0; i < classPathUrls.size(); i++) {
+ String url = (String)classPathUrls.get(i);
+ properties.setProperty("classPathUrl." + i, url);
+ }
+
+ for (int i = 0; i < surefireClassPathUrls.size(); i++) {
+ String url = (String)surefireClassPathUrls.get(i);
+ properties.setProperty("surefireClassPathUrl." + i, url);
+ }
+
+ properties.setProperty("childDelegation", String.valueOf(childDelegation));
+ properties.setProperty("enableAssertions", String.valueOf(enableAssertions));
+ properties.setProperty("useSystemClassLoader", String.valueOf(useSystemClassLoader()));
+ properties.setProperty("useManifestOnlyJar", String.valueOf(useManifestOnlyJar()));
+ properties.setProperty("failIfNoTests", String.valueOf(failIfNoTests));
+ properties.setProperty("mainBundleName", mainBundleName);
+ }
+
+ private File writePropertiesFile(String name, Properties properties) throws IOException {
+ File file = File.createTempFile(name, "tmp");
+ if (!forkConfiguration.isDebug()) {
+ file.deleteOnExit();
+ }
+
+ writePropertiesFile(file, name, properties);
+
+ return file;
+ }
+
+ private void writePropertiesFile(File file, String name, Properties properties) throws IOException {
+ FileOutputStream out = new FileOutputStream(file);
+
+ try {
+ properties.store(out, name);
+ } finally {
+ IOUtil.close(out);
+ }
+ }
+
+ private void addPropertiesForTypeHolder(List typeHolderList, Properties properties, String propertyPrefix) {
+ for (int i = 0; i < typeHolderList.size(); i++) {
+ Object[] report = (Object[])typeHolderList.get(i);
+
+ String className = (String)report[0];
+ Object[] params = (Object[])report[1];
+
+ properties.setProperty(propertyPrefix + i, className);
+
+ if (params != null) {
+ String paramProperty = convert(params[0]);
+ String typeProperty = params[0].getClass().getName();
+ for (int j = 1; j < params.length; j++) {
+ paramProperty += "|";
+ typeProperty += "|";
+ if (params[j] != null) {
+ paramProperty += convert(params[j]);
+ typeProperty += params[j].getClass().getName();
+ }
+ }
+ properties.setProperty(propertyPrefix + i + PARAMS_SUFIX, paramProperty);
+ properties.setProperty(propertyPrefix + i + TYPES_SUFIX, typeProperty);
+ }
+ }
+ }
+
+ private static String convert(Object param) {
+ if (param instanceof File[]) {
+ File[] files = (File[])param;
+ return "[" + StringUtils.join(files, ",") + "]";
+ } else if (param instanceof Properties) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ ((Properties)param).store(baos, "");
+ return new String(baos.toByteArray(), "8859_1");
+ } catch (Exception e) {
+ throw new RuntimeException("bug in property conversion", e);
+ }
+ } else {
+ return param.toString();
+ }
+ }
+
+ private final boolean useSystemClassLoader() {
+ return forkConfiguration.isUseSystemClassLoader() && (isForked || forkConfiguration.isForking());
+ }
+
+ private final boolean useManifestOnlyJar() {
+ return forkConfiguration.isUseSystemClassLoader() && forkConfiguration.isUseManifestOnlyJar();
+ }
+
+ private int fork(Properties properties, boolean showHeading, boolean showFooter) throws SurefireBooterForkException {
+ File surefireProperties;
+ File systemProperties = null;
+ try {
+ surefireProperties = writePropertiesFile("surefire", properties);
+ if (forkConfiguration.getSystemProperties() != null) {
+ systemProperties = writePropertiesFile("surefire", forkConfiguration.getSystemProperties());
+ }
+ } catch (IOException e) {
+ throw new SurefireBooterForkException("Error creating properties files for forking", e);
+ }
+
+ /*
+ System.out.println("cp: " + classPathUrls);
+ System.out.println("scp: " + surefireClassPathUrls);
+ System.out.println("sbcp: " + surefireBootClassPathUrls);
+ */
+
+ List bootClasspath = new ArrayList(surefireBootClassPathUrls.size());
+
+ bootClasspath.addAll(surefireBootClassPathUrls);
+
+ /**
+ * For OSGi, we don't want to polute the system classpath
+ */
+ /*
+ if (useSystemClassLoader()) {
+ bootClasspath.addAll(classPathUrls);
+ }
+ */
+
+ Commandline cli =
+ forkConfiguration.createCommandLine(bootClasspath, useManifestOnlyJar());
+
+ cli.createArg().setFile(surefireProperties);
+
+ if (systemProperties != null) {
+ cli.createArg().setFile(systemProperties);
+ }
+
+ ForkingStreamConsumer out = getForkingStreamConsumer(showHeading, showFooter, redirectTestOutputToFile);
+
+ StreamConsumer err;
+
+ if (redirectTestOutputToFile) {
+ err = out;
+ } else {
+ err = getForkingStreamConsumer(showHeading, showFooter, redirectTestOutputToFile);
+ }
+
+ if (forkConfiguration.isDebug()) {
+ System.out.println("Forking command line: " + cli);
+ }
+
+ int returnCode;
+
+ try {
+ returnCode =
+ org.apache.maven.surefire.booter.shade.org.codehaus.plexus.util.cli.CommandLineUtils
+ .executeCommandLine(cli, out, err, forkedProcessTimeoutInSeconds);
+ } catch (org.apache.maven.surefire.booter.shade.org.codehaus.plexus.util.cli.CommandLineException e) {
+ throw new SurefireBooterForkException("Error while executing forked tests.", e);
+ }
+
+ if (redirectTestOutputToFile) {
+ // ensure the FileOutputConsumerProxy flushes/closes the output file
+ try {
+ out.getOutputConsumer().testSetCompleted();
+ } catch (Exception e) {
+ // the FileOutputConsumerProxy might throw an IllegalStateException but that's not of interest now
+ }
+ }
+
+ if (surefireProperties != null && surefireProperties.exists()) {
+ FileInputStream inStream = null;
+ try {
+ inStream = new FileInputStream(surefireProperties);
+
+ properties.load(inStream);
+ } catch (FileNotFoundException e) {
+ throw new SurefireBooterForkException("Unable to reload properties file from forked process", e);
+ } catch (IOException e) {
+ throw new SurefireBooterForkException("Unable to reload properties file from forked process", e);
+ } finally {
+ IOUtil.close(inStream);
+ }
+ }
+
+ return returnCode;
+ }
+
+ private ClassLoader createClassLoader(List classPathUrls, ClassLoader parent) throws MalformedURLException {
+ return createClassLoader(classPathUrls, parent, false);
+ }
+
+ private ClassLoader createClassLoader(List classPathUrls, ClassLoader parent, boolean childDelegation)
+ throws MalformedURLException {
+ Set<URL> urls = new HashSet<URL>();
+
+ for (Iterator i = classPathUrls.iterator(); i.hasNext();) {
+ String url = (String)i.next();
+
+ if (url != null) {
+ File f = new File(url);
+ urls.add(f.toURI().toURL());
+ }
+ }
+ return bundleClassLoader;
+ }
+
+ private static List processStringList(String stringList) {
+ String sl = stringList;
+
+ if (sl.startsWith("[") && sl.endsWith("]")) {
+ sl = sl.substring(1, sl.length() - 1);
+ }
+
+ List list = new ArrayList();
+
+ String[] stringArray = StringUtils.split(sl, ",");
+
+ for (int i = 0; i < stringArray.length; i++) {
+ list.add(stringArray[i].trim());
+ }
+ return list;
+ }
+
+ private static Properties loadProperties(File file) throws IOException {
+ Properties p = new Properties();
+
+ if (file != null && file.exists()) {
+ FileInputStream inStream = new FileInputStream(file);
+ try {
+ p.load(inStream);
+ } finally {
+ IOUtil.close(inStream);
+ }
+ }
+
+ return p;
+ }
+
+ private static void setSystemProperties(File file) throws IOException {
+ Properties p = loadProperties(file);
+
+ for (Iterator i = p.keySet().iterator(); i.hasNext();) {
+ String key = (String)i.next();
+
+ System.setProperty(key, p.getProperty(key));
+ }
+ }
+
+ private static Object[] constructParamObjects(String paramProperty, String typeProperty) {
+ Object[] paramObjects = null;
+ if (paramProperty != null) {
+ // bit of a glitch that it need sto be done twice to do an odd number of vertical bars (eg |||, |||||).
+ String[] params =
+ StringUtils.split(StringUtils.replace(StringUtils.replace(paramProperty, "||", "| |"), "||", "| |"),
+ "|");
+ String[] types =
+ StringUtils
+ .split(StringUtils.replace(StringUtils.replace(typeProperty, "||", "| |"), "||", "| |"), "|");
+
+ paramObjects = new Object[params.length];
+
+ for (int i = 0; i < types.length; i++) {
+ if (types[i].trim().length() == 0) {
+ params[i] = null;
+ } else if (types[i].equals(String.class.getName())) {
+ paramObjects[i] = params[i];
+ } else if (types[i].equals(File.class.getName())) {
+ paramObjects[i] = new File(params[i]);
+ } else if (types[i].equals(File[].class.getName())) {
+ List stringList = processStringList(params[i]);
+ File[] fileList = new File[stringList.size()];
+ for (int j = 0; j < stringList.size(); j++) {
+ fileList[j] = new File((String)stringList.get(j));
+ }
+ paramObjects[i] = fileList;
+ } else if (types[i].equals(ArrayList.class.getName())) {
+ paramObjects[i] = processStringList(params[i]);
+ } else if (types[i].equals(Boolean.class.getName())) {
+ paramObjects[i] = Boolean.valueOf(params[i]);
+ } else if (types[i].equals(Integer.class.getName())) {
+ paramObjects[i] = Integer.valueOf(params[i]);
+ } else if (types[i].equals(Properties.class.getName())) {
+ final Properties result = new Properties();
+ final String value = params[i];
+ try {
+ ByteArrayInputStream bais = new ByteArrayInputStream(value.getBytes("8859_1"));
+ result.load(bais);
+ } catch (Exception e) {
+ throw new RuntimeException("bug in property conversion", e);
+ }
+ paramObjects[i] = result;
+ } else {
+ // TODO: could attempt to construct with a String constructor if needed
+ throw new IllegalArgumentException("Unknown parameter type: " + types[i]);
+ }
+ }
+ }
+ return paramObjects;
+ }
+
+ /**
+ * This method is invoked when Surefire is forked - this method parses and organizes the arguments passed to it and
+ * then calls the Surefire class' run method. <p/> The system exit code will be 1 if an exception is thrown.
+ *
+ * @param args
+ */
+ public static void main(String[] args) throws Throwable {
+ // noinspection CatchGenericClass,OverlyBroadCatchBlock
+ try {
+ if (args.length > 1) {
+ setSystemProperties(new File(args[1]));
+ }
+
+ File surefirePropertiesFile = new File(args[0]);
+ Properties p = loadProperties(surefirePropertiesFile);
+
+ SortedMap classPathUrls = new TreeMap();
+
+ SortedMap surefireClassPathUrls = new TreeMap();
+
+ OSGiSurefireBooter surefireBooter = new OSGiSurefireBooter(true);
+
+ ForkConfiguration forkConfiguration = new ForkConfiguration();
+ forkConfiguration.setForkMode("never");
+ surefireBooter.setForkConfiguration(forkConfiguration);
+
+ for (Enumeration e = p.propertyNames(); e.hasMoreElements();) {
+ String name = (String)e.nextElement();
+
+ if (name.startsWith(REPORT_PROPERTY_PREFIX) && !name.endsWith(PARAMS_SUFIX)
+ && !name.endsWith(TYPES_SUFIX)) {
+ String className = p.getProperty(name);
+
+ String params = p.getProperty(name + PARAMS_SUFIX);
+ String types = p.getProperty(name + TYPES_SUFIX);
+ surefireBooter.addReport(className, constructParamObjects(params, types));
+ } else if (name.startsWith(TEST_SUITE_PROPERTY_PREFIX) && !name.endsWith(PARAMS_SUFIX)
+ && !name.endsWith(TYPES_SUFIX)) {
+ String className = p.getProperty(name);
+
+ String params = p.getProperty(name + PARAMS_SUFIX);
+ String types = p.getProperty(name + TYPES_SUFIX);
+ surefireBooter.addTestSuite(className, constructParamObjects(params, types));
+ } else if (name.startsWith("classPathUrl.")) {
+ classPathUrls.put(Integer.valueOf(name.substring(name.indexOf('.') + 1)), p.getProperty(name));
+ } else if (name.startsWith("surefireClassPathUrl.")) {
+ surefireClassPathUrls.put(Integer.valueOf(name.substring(name.indexOf('.') + 1)), p
+ .getProperty(name));
+ } else if (name.startsWith("surefireBootClassPathUrl.")) {
+ surefireBooter.addSurefireBootClassPathUrl(p.getProperty(name));
+ } else if ("childDelegation".equals(name)) {
+ surefireBooter.childDelegation = Boolean.valueOf(p.getProperty("childDelegation")).booleanValue();
+ } else if ("enableAssertions".equals(name)) {
+ surefireBooter.enableAssertions = Boolean.valueOf(p.getProperty("enableAssertions")).booleanValue();
+ } else if ("useSystemClassLoader".equals(name)) {
+ surefireBooter.forkConfiguration.setUseSystemClassLoader(Boolean.valueOf(p
+ .getProperty("useSystemClassLoader")).booleanValue());
+ } else if ("useManifestOnlyJar".equals(name)) {
+ surefireBooter.forkConfiguration.setUseManifestOnlyJar(Boolean.valueOf(p
+ .getProperty("useManifestOnlyJar")).booleanValue());
+ } else if ("failIfNoTests".equals(name)) {
+ surefireBooter.setFailIfNoTests(Boolean.valueOf(p.getProperty("failIfNoTests")).booleanValue());
+ } else if ("mainBundleName".equals(name)) {
+ surefireBooter.setMainBundleName(p.getProperty("mainBundleName"));
+ }
+ }
+
+ for (Iterator cpi = classPathUrls.keySet().iterator(); cpi.hasNext();) {
+ String url = (String)classPathUrls.get(cpi.next());
+ surefireBooter.addClassPathUrl(url);
+ }
+
+ for (Iterator scpi = surefireClassPathUrls.keySet().iterator(); scpi.hasNext();) {
+ String url = (String)surefireClassPathUrls.get(scpi.next());
+ surefireBooter.addSurefireClassPathUrl(url);
+ }
+
+ String testSet = p.getProperty("testSet");
+ int result;
+ if (testSet != null) {
+ result = surefireBooter.runSuitesInProcess(testSet, p);
+ } else {
+ result = surefireBooter.runSuitesInProcess();
+ }
+
+ surefireBooter.writePropertiesFile(surefirePropertiesFile, "surefire", p);
+
+ // noinspection CallToSystemExit
+ System.exit(result);
+ } catch (Throwable t) {
+ // Just throwing does getMessage() and a local trace - we want to call printStackTrace for a full trace
+ // noinspection UseOfSystemOutOrSystemErr
+ t.printStackTrace(System.err);
+ // noinspection ProhibitedExceptionThrown,CallToSystemExit
+ System.exit(1);
+ }
+ }
+
+ public void setChildDelegation(boolean childDelegation) {
+ this.childDelegation = childDelegation;
+ }
+
+ private ForkingStreamConsumer getForkingStreamConsumer(boolean showHeading,
+ boolean showFooter,
+ boolean redirectTestOutputToFile) {
+ OutputConsumer outputConsumer = new StandardOutputConsumer();
+
+ if (redirectTestOutputToFile) {
+ outputConsumer = new FileOutputConsumerProxy(outputConsumer, getReportsDirectory());
+ }
+
+ if (!showHeading) {
+ outputConsumer = new SupressHeaderOutputConsumerProxy(outputConsumer);
+ }
+ if (!showFooter) {
+ outputConsumer = new SupressFooterOutputConsumerProxy(outputConsumer);
+ }
+
+ return new ForkingStreamConsumer(outputConsumer);
+ }
+
+ public void setEnableAssertions(boolean enableAssertions) {
+ this.enableAssertions = enableAssertions;
+ }
+
+ public void setForkedProcessTimeoutInSeconds(int forkedProcessTimeoutInSeconds) {
+ this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds;
+ }
+
+ private String mainBundleName;
+
+ public void setMainBundleName(String mainBundleName) {
+ this.mainBundleName = mainBundleName;
+ }
+
+ private Object host;
+ private BundleClassLoader bundleClassLoader;
+
+ public Object start() throws Exception {
+ Set<URL> urls = new HashSet<URL>();
+
+ // Merge the two classpaths so that all of them will be OSGi-enabled
+ Set<String> cps = new HashSet<String>(classPathUrls);
+ cps.addAll(surefireClassPathUrls);
+
+ for (String url: cps) {
+ if (url != null) {
+ File f = new File(url);
+ try {
+ urls.add(f.toURI().toURL());
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ host = createEquinox(urls);
+ BundleContext context = startEquinox(host);
+ Bundle mainBundle = null;
+ for (Bundle bundle : context.getBundles()) {
+ // Fragement bundle cannot be used to load class, use the main bundle
+ if (mainBundleName.equals(bundle.getSymbolicName())) {
+ mainBundle = bundle;
+ break;
+ }
+ }
+
+ bundleClassLoader = new BundleClassLoader(mainBundle, null);
+ if (assertionStatusMethod != null) {
+ try {
+ Object[] args = new Object[] {enableAssertions ? Boolean.TRUE : Boolean.FALSE};
+ assertionStatusMethod.invoke(bundleClassLoader, args);
+ } catch (IllegalAccessException e) {
+ throw new NestedRuntimeException("Unable to access the assertion enablement method", e);
+ } catch (InvocationTargetException e) {
+ throw new NestedRuntimeException("Unable to invoke the assertion enablement method", e);
+ }
+ }
+
+ return host;
+ }
+
+ public void stop() {
+ if (host != null) {
+ try {
+ stopEquinox(host);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ host = null;
+ bundleClassLoader = null;
+ }
+ }
+
+ private static Object createEquinox(Set<URL> urls) throws Exception {
+ String name = "org.apache.tuscany.sca.node.equinox.launcher.EquinoxHost";
+ Class<?> cls = Class.forName(name);
+ Constructor<?> ctor = cls.getConstructor(Set.class);
+ return ctor.newInstance(urls);
+ }
+
+ private static BundleContext startEquinox(Object host) throws Exception {
+ Method start = host.getClass().getMethod("start");
+ return (BundleContext)start.invoke(host);
+ }
+
+ private static void stopEquinox(Object host) throws Exception {
+ Method stop = host.getClass().getMethod("stop");
+ stop.invoke(host);
+ }
+
+ /**
+ * Returns a string representation of the given bundle.
+ *
+ * @param b
+ * @param verbose
+ * @return
+ */
+ static String string(Bundle bundle, boolean verbose) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(bundle.getBundleId()).append(" ").append(bundle.getSymbolicName());
+ int s = bundle.getState();
+ if ((s & Bundle.UNINSTALLED) != 0) {
+ sb.append(" UNINSTALLED");
+ }
+ if ((s & Bundle.INSTALLED) != 0) {
+ sb.append(" INSTALLED");
+ }
+ if ((s & Bundle.RESOLVED) != 0) {
+ sb.append(" RESOLVED");
+ }
+ if ((s & Bundle.STARTING) != 0) {
+ sb.append(" STARTING");
+ }
+ if ((s & Bundle.STOPPING) != 0) {
+ sb.append(" STOPPING");
+ }
+ if ((s & Bundle.ACTIVE) != 0) {
+ sb.append(" ACTIVE");
+ }
+
+ if (verbose) {
+ sb.append(" ").append(bundle.getLocation());
+ sb.append(" ").append(bundle.getHeaders());
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/maven-plugins/tags/maven-osgi-junit-plugin-1.0/src/main/java/org/apache/tuscany/maven/plugin/surefire/OSGiSurefirePlugin.java b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/src/main/java/org/apache/tuscany/maven/plugin/surefire/OSGiSurefirePlugin.java
new file mode 100644
index 0000000000..90e5911f42
--- /dev/null
+++ b/maven-plugins/tags/maven-osgi-junit-plugin-1.0/src/main/java/org/apache/tuscany/maven/plugin/surefire/OSGiSurefirePlugin.java
@@ -0,0 +1,1310 @@
+/*
+ * 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.
+ */
+
+package org.apache.tuscany.maven.plugin.surefire;
+
+import static org.osgi.framework.Constants.BUNDLE_MANIFESTVERSION;
+import static org.osgi.framework.Constants.BUNDLE_NAME;
+import static org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME;
+import static org.osgi.framework.Constants.BUNDLE_VERSION;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.jar.Attributes;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
+import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.surefire.booter.SurefireBooterForkException;
+import org.apache.maven.surefire.booter.SurefireExecutionException;
+import org.apache.maven.surefire.booter.shade.org.codehaus.plexus.util.StringUtils;
+import org.apache.maven.surefire.report.BriefConsoleReporter;
+import org.apache.maven.surefire.report.BriefFileReporter;
+import org.apache.maven.surefire.report.ConsoleReporter;
+import org.apache.maven.surefire.report.DetailedConsoleReporter;
+import org.apache.maven.surefire.report.FileReporter;
+import org.apache.maven.surefire.report.ForkingConsoleReporter;
+import org.apache.maven.surefire.report.XMLReporter;
+import org.apache.maven.toolchain.Toolchain;
+import org.apache.maven.toolchain.ToolchainManager;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+/**
+ * Derived from maven-surefire-plugin 2.4.3
+ * Run tests using Surefire.
+ *
+ * @requiresDependencyResolution test
+ * @goal test
+ * @phase test
+ */
+public class OSGiSurefirePlugin extends AbstractMojo {
+
+ /**
+ * Set this to 'true' to skip running tests, but still compile them. Its use is NOT RECOMMENDED, but quite
+ * convenient on occasion.
+ *
+ * @parameter expression="${skipTests}"
+ * @since 2.4
+ */
+ protected boolean skipTests;
+
+ /**
+ * DEPRECATED This old parameter is just like skipTests, but bound to the old property maven.test.skip.exec.
+ * Use -DskipTests instead; it's shorter.
+ *
+ * @deprecated
+ * @parameter expression="${maven.test.skip.exec}"
+ * @since 2.3
+ */
+ protected boolean skipExec;
+
+ /**
+ * Set this to 'true' to bypass unit tests entirely. Its use is NOT RECOMMENDED, especially if you
+ * enable it using the "maven.test.skip" property, because maven.test.skip disables both running the
+ * tests and compiling the tests. Consider using the skipTests parameter instead.
+ *
+ * @parameter expression="${maven.test.skip}"
+ */
+ protected boolean skip;
+
+ /**
+ * Set this to true to ignore a failure during testing. Its use is NOT RECOMMENDED, but quite convenient on
+ * occasion.
+ *
+ * @parameter expression="${maven.test.failure.ignore}"
+ */
+ protected boolean testFailureIgnore;
+
+ /**
+ * The base directory of the project being tested. This can be obtained in your unit test by
+ * System.getProperty("basedir").
+ *
+ * @parameter expression="${basedir}"
+ * @required
+ */
+ protected File basedir;
+
+ /**
+ * The directory containing generated test classes of the project being tested.
+ *
+ * @parameter expression="${project.build.testOutputDirectory}"
+ * @required
+ */
+ protected File testClassesDirectory;
+
+ /**
+ * The directory containing generated classes of the project being tested.
+ *
+ * @parameter expression="${project.build.outputDirectory}"
+ * @required
+ */
+ protected File classesDirectory;
+
+ /**
+ * The Maven Project Object
+ *
+ * @parameter expression="${project}"
+ * @required
+ * @readonly
+ */
+ protected MavenProject project;
+
+ /**
+ * The classpath elements of the project being tested.
+ *
+ * @parameter expression="${project.testClasspathElements}"
+ * @required
+ * @readonly
+ */
+ protected List classpathElements;
+
+ /**
+ * Additional elements to be appended to the classpath.
+ *
+ * @parameter
+ * @since 2.4
+ */
+ protected List additionalClasspathElements;
+
+ /**
+ * Base directory where all reports are written to.
+ *
+ * @parameter expression="${project.build.directory}/surefire-osgi-reports"
+ */
+ protected File reportsDirectory;
+
+ /**
+ * The test source directory containing test class sources.
+ *
+ * @parameter expression="${project.build.testSourceDirectory}"
+ * @required
+ * @since 2.2
+ */
+ protected File testSourceDirectory;
+
+ /**
+ * Specify this parameter to run individual tests by file name, overriding the <code>includes/excludes</code>
+ * parameters. Each pattern you specify here will be used to create an
+ * include pattern formatted like <code>**&#47;${test}.java</code>, so you can just type "-Dtest=MyTest"
+ * to run a single test called "foo/MyTest.java". This parameter will override the TestNG suiteXmlFiles
+ * parameter.
+ *
+ * @parameter expression="${test}"
+ */
+ protected String test;
+
+ /**
+ * List of patterns (separated by commas) used to specify the tests that should be included in testing. When not
+ * specified and when the <code>test</code> parameter is not specified, the default includes will be
+ * <code>**&#47;Test*.java **&#47;*Test.java **&#47;*TestCase.java</code>. This parameter is ignored if
+ * TestNG suiteXmlFiles are specified.
+ *
+ * @parameter
+ */
+ protected List includes;
+
+ /**
+ * List of patterns (separated by commas) used to specify the tests that should be excluded in testing. When not
+ * specified and when the <code>test</code> parameter is not specified, the default excludes will be
+ * <code>**&#47;*$*</code> (which excludes all inner classes). This parameter is ignored if
+ * TestNG suiteXmlFiles are specified.
+ *
+ * @parameter
+ */
+ protected List excludes;
+
+ /**
+ * ArtifactRepository of the localRepository. To obtain the directory of localRepository in unit tests use
+ * System.setProperty( "localRepository").
+ *
+ * @parameter expression="${localRepository}"
+ * @required
+ * @readonly
+ */
+ protected ArtifactRepository localRepository;
+
+ /**
+ * List of System properties to pass to the JUnit tests.
+ *
+ * @parameter
+ */
+ protected Properties systemProperties;
+
+ /**
+ * List of properties for configuring all TestNG related configurations. This is the new
+ * preferred method of configuring TestNG.
+ *
+ * @parameter
+ * @since 2.4
+ */
+ protected Properties properties;
+
+ /**
+ * Map of of plugin artifacts.
+ *
+ * @parameter expression="${plugin.artifactMap}"
+ * @required
+ * @readonly
+ */
+ protected Map pluginArtifactMap;
+
+ /**
+ * @parameter expression="${plugin.groupId}"
+ * @required
+ * @readonly
+ */
+ protected String pluginGroupId;
+ /**
+ * @parameter expression="${plugin.artifactId}"
+ * @required
+ * @readonly
+ */
+ protected String pluginArtifactId;
+ /**
+ * @parameter expression="${plugin.version}"
+ * @required
+ * @readonly
+ */
+ protected String pluginVersion;
+
+ /**
+ * Map of of project artifacts.
+ *
+ * @parameter expression="${project.artifactMap}"
+ * @required
+ * @readonly
+ */
+ protected Map projectArtifactMap;
+
+ /**
+ * Option to print summary of test suites or just print the test cases that has errors.
+ *
+ * @parameter expression="${surefire.printSummary}" default-value="true"
+ */
+ protected boolean printSummary;
+
+ /**
+ * Selects the formatting for the test report to be generated. Can be set as brief or plain.
+ *
+ * @parameter expression="${surefire.reportFormat}" default-value="brief"
+ */
+ protected String reportFormat;
+
+ /**
+ * Option to generate a file test report or just output the test report to the console.
+ *
+ * @parameter expression="${surefire.useFile}" default-value="true"
+ */
+ protected boolean useFile;
+
+ /**
+ * When forking, set this to true to redirect the unit test standard output to a file (found in
+ * reportsDirectory/testName-output.txt).
+ *
+ * @parameter expression="${maven.test.redirectTestOutputToFile}" default-value="false"
+ * @since 2.3
+ */
+ protected boolean redirectTestOutputToFile;
+
+ /**
+ * Set this to "true" to cause a failure if there are no tests to run. Defaults to false.
+ *
+ * @parameter expression="${failIfNoTests}"
+ * @since 2.4
+ */
+ protected Boolean failIfNoTests;
+
+ /**
+ * Option to specify the forking mode. Can be "never", "once" or "always". "none" and "pertest" are also accepted
+ * for backwards compatibility.
+ *
+ * @parameter expression="${forkMode}" default-value="once"
+ * @since 2.1
+ */
+ protected String forkMode;
+
+ /**
+ * Option to specify the jvm (or path to the java executable) to use with the forking options. For the default, the
+ * jvm will be the same as the one used to run Maven.
+ *
+ * @parameter expression="${jvm}"
+ * @since 2.1
+ */
+ protected String jvm;
+
+ /**
+ * Arbitrary JVM options to set on the command line.
+ *
+ * @parameter expression="${argLine}"
+ * @since 2.1
+ */
+ protected String argLine;
+
+ /**
+ * Attach a debugger to the forked JVM. If set to "true", the process will suspend and
+ * wait for a debugger to attach on port 5005. If set to some other string, that
+ * string will be appended to the argLine, allowing you to configure arbitrary
+ * debuggability options (without overwriting the other options specified in the argLine).
+ *
+ * @parameter expression="${maven.surefire.debug}"
+ * @since 2.4
+ */
+ protected String debugForkedProcess;
+
+ /**
+ * Kill the forked test process after a certain number of seconds. If set to 0,
+ * wait forever for the process, never timing out.
+ *
+ * @parameter expression="${surefire.timeout}"
+ * @since 2.4
+ */
+ protected int forkedProcessTimeoutInSeconds;
+
+ /**
+ * Additional environments to set on the command line.
+ *
+ * @parameter
+ * @since 2.1.3
+ */
+ protected Map environmentVariables = new HashMap();
+
+ /**
+ * Command line working directory.
+ *
+ * @parameter expression="${basedir}"
+ * @since 2.1.3
+ */
+ protected File workingDirectory;
+
+ /**
+ * When false it makes tests run using the standard classloader delegation instead of the default Maven isolated
+ * classloader. Only used when forking (forkMode is not "none").<br/> Setting it to false helps with some problems
+ * caused by conflicts between xml parsers in the classpath and the Java 5 provider parser.
+ *
+ * @parameter expression="${childDelegation}" default-value="false"
+ * @since 2.1
+ */
+ protected boolean childDelegation;
+
+ /**
+ * (TestNG only) Groups for this test. Only classes/methods/etc decorated with one of the groups specified here will be included
+ * in test run, if specified. This parameter is overridden if suiteXmlFiles are specified.
+ *
+ * @parameter expression="${groups}"
+ * @since 2.2
+ */
+ protected String groups;
+
+ /**
+ * (TestNG only) Excluded groups. Any methods/classes/etc with one of the groups specified in this list will specifically not be
+ * run. This parameter is overridden if suiteXmlFiles are specified.
+ *
+ * @parameter expression="${excludedGroups}"
+ * @since 2.2
+ */
+ protected String excludedGroups;
+
+ /**
+ * (TestNG only) List of TestNG suite xml file locations, seperated by commas. Note that suiteXmlFiles is incompatible
+ * with several other parameters on this plugin, like includes/excludes. This parameter is ignored if
+ * the "test" parameter is specified (allowing you to run a single test instead of an entire suite).
+ *
+ * @parameter
+ * @since 2.2
+ */
+ protected File[] suiteXmlFiles;
+
+ /**
+ * Allows you to specify the name of the JUnit artifact. If not set, <code>junit:junit</code> will be used.
+ *
+ * @parameter expression="${junitArtifactName}" default-value="junit:junit"
+ * @since 2.3.1
+ */
+ protected String junitArtifactName;
+
+ /**
+ * Allows you to specify the name of the TestNG artifact. If not set, <code>org.testng:testng</code> will be used.
+ *
+ * @parameter expression="${testNGArtifactName}" default-value="org.testng:testng"
+ * @since 2.3.1
+ */
+ protected String testNGArtifactName;
+
+ /**
+ * (TestNG only) The attribute thread-count allows you to specify how many threads should be allocated for this execution. Only
+ * makes sense to use in conjunction with parallel.
+ *
+ * @parameter expression="${threadCount}"
+ * @since 2.2
+ */
+ protected int threadCount;
+
+ /**
+ * (TestNG only) When you use the parallel attribute, TestNG will try to run all your test methods in separate threads, except for
+ * methods that depend on each other, which will be run in the same thread in order to respect their order of
+ * execution.
+ *
+ * @parameter expression="${parallel}"
+ * @todo test how this works with forking, and console/file output parallelism
+ * @since 2.2
+ */
+ protected String parallel;
+
+ /**
+ * Whether to trim the stack trace in the reports to just the lines within the test, or show the full trace.
+ *
+ * @parameter expression="${trimStackTrace}" default-value="true"
+ * @since 2.2
+ */
+ protected boolean trimStackTrace;
+
+ /**
+ * Resolves the artifacts needed.
+ *
+ * @component
+ */
+ protected ArtifactResolver artifactResolver;
+
+ /**
+ * Creates the artifact
+ *
+ * @component
+ */
+ protected ArtifactFactory artifactFactory;
+
+ /**
+ * The plugin remote repositories declared in the pom.
+ *
+ * @parameter expression="${project.pluginArtifactRepositories}"
+ * @since 2.2
+ */
+ protected List remoteRepositories;
+
+ /**
+ * For retrieval of artifact's metadata.
+ *
+ * @component
+ */
+ protected ArtifactMetadataSource metadataSource;
+
+ protected static final String BRIEF_REPORT_FORMAT = "brief";
+
+ protected static final String PLAIN_REPORT_FORMAT = "plain";
+
+ protected Properties originalSystemProperties;
+
+ /**
+ * Flag to disable the generation of report files in xml format.
+ *
+ * @parameter expression="${disableXmlReport}" default-value="false"
+ * @since 2.2
+ */
+ protected boolean disableXmlReport;
+
+ /**
+ * Option to pass dependencies to the system's classloader instead of using an isolated class loader when forking.
+ * Prevents problems with JDKs which implement the service provider lookup mechanism by using the system's
+ * classloader. Default value is "true".
+ *
+ * @parameter expression="${surefire.useSystemClassLoader}"
+ * @since 2.3
+ */
+ protected Boolean useSystemClassLoader;
+
+ /**
+ * By default, Surefire forks your tests using a manifest-only jar; set this parameter
+ * to "false" to force it to launch your tests with a plain old Java classpath.
+ * (See http://maven.apache.org/plugins/maven-surefire-plugin/examples/class-loading.html
+ * for a more detailed explanation of manifest-only jars and their benefits.)
+ *
+ * Default value is "true". Beware, setting this to "false" may cause your tests to
+ * fail on Windows if your classpath is too long.
+ *
+ * @parameter expression="${surefire.useManifestOnlyJar}" default-value="true"
+ * @since 2.4.3
+ */
+ protected boolean useManifestOnlyJar;
+
+ /**
+ * By default, Surefire enables JVM assertions for the execution of your test cases. To disable the assertions, set
+ * this flag to <code>false</code>.
+ *
+ * @parameter expression="${enableAssertions}" default-value="true"
+ * @since 2.3.1
+ */
+ protected boolean enableAssertions;
+
+ /**
+ * The current build session instance.
+ *
+ * @parameter expression="${session}"
+ * @required
+ * @readonly
+ */
+ protected MavenSession session;
+
+ public void execute() throws MojoExecutionException, MojoFailureException {
+ if (project.getPackaging().equals("pom")) {
+ return;
+ }
+
+ if (verifyParameters()) {
+ OSGiSurefireBooter surefireBooter = constructSurefireBooter();
+
+ Log log = getLog();
+ Set<String> jarFiles = new HashSet<String>();
+
+ /*
+ for (Object o : project.getArtifacts()) {
+ Artifact a = (Artifact)o;
+ if ("pom".equals(a.getType())) {
+ // Skip pom projects
+ continue;
+ }
+ try {
+ if (log.isDebugEnabled()) {
+ log.debug("Adding: " + a);
+ }
+ jarFiles.add(a.getFile().toURI().toURL());
+ } catch (MalformedURLException e) {
+ getLog().error(e);
+ }
+ }
+ */
+
+ /*
+ * Add org.apache.tuscany.sca:tuscany-extensibility-osgi module
+ */
+ Artifact ext = getArtifact("org.apache.tuscany.sca", "tuscany-extensibility-equinox");
+ if (log.isDebugEnabled()) {
+ log.debug("Adding: " + ext);
+ }
+ jarFiles.add(ext.getFile().getAbsolutePath());
+
+ Artifact con = getArtifact("org.apache.tuscany.sca", "tuscany-contribution-osgi");
+ if (log.isDebugEnabled()) {
+ log.debug("Adding: " + con);
+ }
+ jarFiles.add(con.getFile().getAbsolutePath());
+
+ String name = project.getBuild().getFinalName();
+ String mainBundleName = null;
+ File mainJar = new File(project.getBuild().getDirectory(), name + "-osgi.jar");
+ File testJar = new File(project.getBuild().getDirectory(), name + "-osgi-tests.jar");
+ try {
+ Manifest manifest = createMainBundle();
+ mainBundleName = manifest.getMainAttributes().getValue(BUNDLE_SYMBOLICNAME);
+ int sc = mainBundleName.indexOf(';');
+ if (sc != -1) {
+ mainBundleName = mainBundleName.substring(0, sc);
+ }
+ generateJar(classesDirectory, mainJar, manifest);
+ Manifest testManifest = createTestFragment(manifest);
+ generateJar(testClassesDirectory, testJar, testManifest);
+ jarFiles.add(mainJar.getAbsolutePath());
+ jarFiles.add(testJar.getAbsolutePath());
+ } catch (IOException e) {
+ getLog().error(e);
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Main bundle: " + mainBundleName);
+ }
+ surefireBooter.setMainBundleName(mainBundleName);
+ for (String url : jarFiles) {
+ surefireBooter.addClassPathUrl(url);
+ }
+
+ getLog().info("Surefire report directory: " + reportsDirectory);
+
+ int result;
+ try {
+ result = surefireBooter.run();
+ } catch (SurefireBooterForkException e) {
+ throw new MojoExecutionException(e.getMessage(), e);
+ } catch (SurefireExecutionException e) {
+ throw new MojoExecutionException(e.getMessage(), e);
+ }
+
+ if (originalSystemProperties != null && !surefireBooter.isForking()) {
+ // restore system properties, only makes sense when not forking..
+ System.setProperties(originalSystemProperties);
+ }
+
+ if (result == 0)
+ return;
+
+ String msg;
+
+ if (result == OSGiSurefireBooter.NO_TESTS_EXIT_CODE) {
+ if ((failIfNoTests == null) || !failIfNoTests.booleanValue())
+ return;
+ // TODO: i18n
+ throw new MojoFailureException(
+ "No tests were executed! (Set -DfailIfNoTests=false to ignore this error.)");
+ } else {
+ // TODO: i18n
+ msg =
+ "There are test failures.\n\nPlease refer to " + reportsDirectory
+ + " for the individual test results.";
+
+ }
+
+ if (testFailureIgnore) {
+ getLog().error(msg);
+ } else {
+ throw new MojoFailureException(msg);
+ }
+ }
+ }
+
+ protected boolean verifyParameters() throws MojoFailureException {
+ if (skip || skipTests || skipExec) {
+ getLog().info("Tests are skipped.");
+ return false;
+ }
+
+ if (!testClassesDirectory.exists()) {
+ if (failIfNoTests != null && failIfNoTests.booleanValue()) {
+ throw new MojoFailureException("No tests to run!");
+ }
+ getLog().info("No tests to run.");
+ return false;
+ }
+
+ if (useSystemClassLoader != null && ForkConfiguration.FORK_NEVER.equals(forkMode)) {
+ getLog().warn("useSystemClassloader setting has no effect when not forking");
+ }
+
+ return true;
+ }
+
+ /**
+ * Converts old TestNG configuration parameters over to new properties based configuration
+ * method. (if any are defined the old way)
+ */
+ private void convertTestNGParameters() {
+ if (properties == null) {
+ properties = new Properties();
+ }
+
+ if (this.parallel != null) {
+ properties.setProperty("parallel", this.parallel);
+ }
+ if (this.excludedGroups != null) {
+ properties.setProperty("excludegroups", this.excludedGroups);
+ }
+ if (this.groups != null) {
+ properties.setProperty("groups", this.groups);
+ }
+
+ if (this.threadCount > 0) {
+ properties.setProperty("threadcount", new Integer(this.threadCount).toString());
+ }
+ }
+
+ private OSGiSurefireBooter constructSurefireBooter() throws MojoExecutionException, MojoFailureException {
+ OSGiSurefireBooter surefireBooter = new OSGiSurefireBooter();
+
+ // Build up the surefire boot classpath
+ // * org.apache.tuscany.sca:tuscany-maven-surefire-osgi-plugin (non-transitive
+ // to exclude maven dependencies
+ // * org.apache.tuscany.sca:tuscany-node-launcher-equinox (transitive)
+ // * org.apache.maven.surefire:surefire-booter (transitive)
+ // Get the artifact for the OSGi surefire plugin
+ Artifact osgiArtifact =
+ artifactFactory.createArtifact(pluginGroupId,
+ pluginArtifactId,
+ pluginVersion,
+ Artifact.SCOPE_TEST,
+ "maven-plugin");
+ try {
+ artifactResolver.resolve(osgiArtifact, remoteRepositories, localRepository);
+ surefireBooter.addSurefireBootClassPathUrl(osgiArtifact.getFile().getAbsolutePath());
+ } catch (Exception e) {
+ throw new MojoExecutionException("Unable to resolve " + osgiArtifact);
+ }
+
+ Artifact launcher = (Artifact) pluginArtifactMap.get("org.apache.tuscany.sca:tuscany-node-launcher-equinox");
+
+ // Look up the surefire-booter
+ Artifact surefireArtifact = (Artifact)pluginArtifactMap.get("org.apache.maven.surefire:surefire-booter");
+ if (surefireArtifact == null) {
+ throw new MojoExecutionException("Unable to locate surefire-booter in the list of plugin artifacts");
+ }
+
+ surefireArtifact.isSnapshot(); // TODO: this is ridiculous, but it fixes getBaseVersion to be -SNAPSHOT if
+ // needed
+
+ Artifact junitArtifact;
+ Artifact testNgArtifact;
+ try {
+ addArtifact(surefireBooter, surefireArtifact);
+ addArtifact(surefireBooter, launcher);
+
+ junitArtifact = (Artifact)projectArtifactMap.get(junitArtifactName);
+ // SUREFIRE-378, junit can have an alternate artifact name
+ if (junitArtifact == null && "junit:junit".equals(junitArtifactName)) {
+ junitArtifact = (Artifact)projectArtifactMap.get("junit:junit-dep");
+ }
+
+ // TODO: this is pretty manual, but I'd rather not require the plugin > dependencies section right now
+ testNgArtifact = (Artifact)projectArtifactMap.get(testNGArtifactName);
+
+ if (testNgArtifact != null) {
+ VersionRange range = VersionRange.createFromVersionSpec("[4.7,)");
+ if (!range.containsVersion(new DefaultArtifactVersion(testNgArtifact.getVersion()))) {
+ throw new MojoFailureException(
+ "TestNG support requires version 4.7 or above. You have declared version " + testNgArtifact
+ .getVersion());
+ }
+
+ convertTestNGParameters();
+
+ if (this.testClassesDirectory != null) {
+ properties.setProperty("testng.test.classpath", testClassesDirectory.getAbsolutePath());
+ }
+
+ addArtifact(surefireBooter, testNgArtifact);
+
+ // The plugin uses a JDK based profile to select the right testng. We might be explicity using a
+ // different one since its based on the source level, not the JVM. Prune using the filter.
+ addProvider(surefireBooter, "surefire-testng", surefireArtifact.getBaseVersion(), testNgArtifact);
+ } else if (junitArtifact != null && junitArtifact.getBaseVersion().startsWith("4")) {
+ addProvider(surefireBooter, "surefire-junit4", surefireArtifact.getBaseVersion(), null);
+ } else {
+ // add the JUnit provider as default - it doesn't require JUnit to be present,
+ // since it supports POJO tests.
+ addProvider(surefireBooter, "surefire-junit", surefireArtifact.getBaseVersion(), null);
+ }
+ } catch (ArtifactNotFoundException e) {
+ throw new MojoExecutionException("Unable to locate required surefire provider dependency: " + e
+ .getMessage(), e);
+ } catch (InvalidVersionSpecificationException e) {
+ throw new MojoExecutionException("Error determining the TestNG version requested: " + e.getMessage(), e);
+ } catch (ArtifactResolutionException e) {
+ throw new MojoExecutionException("Error to resolving surefire provider dependency: " + e.getMessage(), e);
+ }
+
+ if (suiteXmlFiles != null && suiteXmlFiles.length > 0 && test == null) {
+ if (testNgArtifact == null) {
+ throw new MojoExecutionException("suiteXmlFiles is configured, but there is no TestNG dependency");
+ }
+
+ // TODO: properties should be passed in here too
+ surefireBooter.addTestSuite("org.apache.maven.surefire.testng.TestNGXmlTestSuite",
+ new Object[] {suiteXmlFiles, testSourceDirectory.getAbsolutePath(),
+ testNgArtifact.getVersion(), testNgArtifact.getClassifier(),
+ properties, reportsDirectory});
+ } else {
+ List includes;
+ List excludes;
+
+ if (test != null) {
+ // Check to see if we are running a single test. The raw parameter will
+ // come through if it has not been set.
+
+ // FooTest -> **/FooTest.java
+
+ includes = new ArrayList();
+
+ excludes = new ArrayList();
+
+ if (failIfNoTests == null) {
+ failIfNoTests = Boolean.TRUE;
+ }
+
+ String[] testRegexes = StringUtils.split(test, ",");
+
+ for (int i = 0; i < testRegexes.length; i++) {
+ String testRegex = testRegexes[i];
+ if (testRegex.endsWith(".java")) {
+ testRegex = testRegex.substring(0, testRegex.length() - 5);
+ }
+ // Allow paths delimited by '.' or '/'
+ testRegex = testRegex.replace('.', '/');
+ includes.add("**/" + testRegex + ".java");
+ }
+ } else {
+ includes = this.includes;
+
+ excludes = this.excludes;
+
+ // defaults here, qdox doesn't like the end javadoc value
+ // Have to wrap in an ArrayList as surefire expects an ArrayList instead of a List for some reason
+ if (includes == null || includes.size() == 0) {
+ includes =
+ new ArrayList(Arrays
+ .asList(new String[] {"**/Test*.java", "**/*Test.java", "**/*TestCase.java"}));
+ }
+ if (excludes == null || excludes.size() == 0) {
+ excludes = new ArrayList(Arrays.asList(new String[] {"**/*$*"}));
+ }
+ }
+
+ if (testNgArtifact != null) {
+ surefireBooter.addTestSuite("org.apache.maven.surefire.testng.TestNGDirectoryTestSuite",
+ new Object[] {testClassesDirectory, includes, excludes,
+ testSourceDirectory.getAbsolutePath(),
+ testNgArtifact.getVersion(), testNgArtifact.getClassifier(),
+ properties, reportsDirectory});
+ } else {
+ String junitDirectoryTestSuite;
+ if (junitArtifact != null && junitArtifact.getBaseVersion() != null
+ && junitArtifact.getBaseVersion().startsWith("4")) {
+ junitDirectoryTestSuite = "org.apache.maven.surefire.junit4.JUnit4DirectoryTestSuite";
+ } else {
+ junitDirectoryTestSuite = "org.apache.maven.surefire.junit.JUnitDirectoryTestSuite";
+ }
+
+ // fall back to JUnit, which also contains POJO support. Also it can run
+ // classes compiled against JUnit since it has a dependency on JUnit itself.
+ surefireBooter.addTestSuite(junitDirectoryTestSuite, new Object[] {testClassesDirectory, includes,
+ excludes});
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ getLog().debug("Test Classpath :");
+
+ classpathElements.remove(classesDirectory.getAbsolutePath());
+ classpathElements.remove(testClassesDirectory.getAbsolutePath());
+ /*
+ // Check if we need to add configured classes/test classes directories here.
+ // If they are configured, we should remove the default to avoid conflicts.
+ if (!project.getBuild().getOutputDirectory().equals(classesDirectory.getAbsolutePath())) {
+ classpathElements.remove(project.getBuild().getOutputDirectory());
+ classpathElements.add(classesDirectory.getAbsolutePath());
+ }
+ if (!project.getBuild().getTestOutputDirectory().equals(testClassesDirectory.getAbsolutePath())) {
+ classpathElements.remove(project.getBuild().getTestOutputDirectory());
+ classpathElements.add(testClassesDirectory.getAbsolutePath());
+ }
+ */
+
+ for (Iterator i = classpathElements.iterator(); i.hasNext();) {
+ String classpathElement = (String)i.next();
+
+ getLog().debug(" " + classpathElement);
+
+ surefireBooter.addClassPathUrl(classpathElement);
+ }
+
+ Toolchain tc = getToolchain();
+
+ if (tc != null) {
+ getLog().info("Toolchain in surefire-plugin: " + tc);
+ if (ForkConfiguration.FORK_NEVER.equals(forkMode)) {
+ forkMode = ForkConfiguration.FORK_ONCE;
+ }
+ if (jvm != null) {
+ getLog().warn("Toolchains are ignored, 'executable' parameter is set to " + jvm);
+ } else {
+ jvm = tc.findTool("java"); //NOI18N
+ }
+ }
+
+ if (additionalClasspathElements != null) {
+ for (Iterator i = additionalClasspathElements.iterator(); i.hasNext();) {
+ String classpathElement = (String)i.next();
+
+ getLog().debug(" " + classpathElement);
+
+ surefireBooter.addClassPathUrl(classpathElement);
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // Forking
+ // ----------------------------------------------------------------------
+
+ ForkConfiguration fork = new ForkConfiguration();
+
+ fork.setForkMode(forkMode);
+
+ processSystemProperties(!fork.isForking());
+
+ if (getLog().isDebugEnabled()) {
+ showMap(systemProperties, "system property");
+ }
+
+ if (fork.isForking()) {
+ useSystemClassLoader = useSystemClassLoader == null ? Boolean.TRUE : useSystemClassLoader;
+ fork.setUseSystemClassLoader(useSystemClassLoader.booleanValue());
+ fork.setUseManifestOnlyJar(useManifestOnlyJar);
+
+ fork.setSystemProperties(systemProperties);
+
+ if ("true".equals(debugForkedProcess)) {
+ debugForkedProcess =
+ "-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005";
+ }
+
+ fork.setDebugLine(debugForkedProcess);
+
+ if (jvm == null || "".equals(jvm)) {
+ // use the same JVM as the one used to run Maven (the "java.home" one)
+ jvm = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
+ getLog().debug("Using JVM: " + jvm);
+ }
+
+ fork.setJvmExecutable(jvm);
+
+ if (workingDirectory != null) {
+ fork.setWorkingDirectory(workingDirectory);
+ } else {
+ fork.setWorkingDirectory(basedir);
+ }
+
+ fork.setArgLine(argLine);
+
+ fork.setEnvironmentVariables(environmentVariables);
+
+ if (getLog().isDebugEnabled()) {
+ showMap(environmentVariables, "environment variable");
+
+ fork.setDebug(true);
+ }
+
+ if (argLine != null) {
+ List args = Arrays.asList(argLine.split(" "));
+ if (args.contains("-da") || args.contains("-disableassertions")) {
+ enableAssertions = false;
+ }
+ }
+ }
+
+ surefireBooter.setFailIfNoTests(failIfNoTests == null ? false : failIfNoTests.booleanValue());
+
+ surefireBooter.setForkedProcessTimeoutInSeconds(forkedProcessTimeoutInSeconds);
+
+ surefireBooter.setRedirectTestOutputToFile(redirectTestOutputToFile);
+
+ surefireBooter.setForkConfiguration(fork);
+
+ surefireBooter.setChildDelegation(childDelegation);
+
+ surefireBooter.setEnableAssertions(enableAssertions);
+
+ surefireBooter.setReportsDirectory(reportsDirectory);
+
+ addReporters(surefireBooter, fork.isForking());
+
+ return surefireBooter;
+ }
+
+ private void showMap(Map map, String setting) {
+ for (Iterator i = map.keySet().iterator(); i.hasNext();) {
+ String key = (String)i.next();
+ String value = (String)map.get(key);
+ getLog().debug("Setting " + setting + " [" + key + "]=[" + value + "]");
+ }
+ }
+
+ private void addProvider(OSGiSurefireBooter surefireBooter,
+ String provider,
+ String version,
+ Artifact filteredArtifact) throws ArtifactNotFoundException, ArtifactResolutionException {
+ Artifact providerArtifact =
+ artifactFactory.createDependencyArtifact("org.apache.maven.surefire", provider, VersionRange
+ .createFromVersion(version), "jar", null, Artifact.SCOPE_TEST);
+ ArtifactResolutionResult result = resolveArtifact(filteredArtifact, providerArtifact);
+
+ for (Iterator i = result.getArtifacts().iterator(); i.hasNext();) {
+ Artifact artifact = (Artifact)i.next();
+
+ String key = ArtifactUtils.versionlessKey(artifact);
+ if("junit:junit".equals(key) || "jnuit:junit-dep".equals(key)) {
+ // Skip junit as it will be pulled from the test case dependencies
+ continue;
+ }
+ getLog().debug("Adding to surefire test classpath: " + artifact.getFile().getAbsolutePath());
+
+ surefireBooter.addSurefireClassPathUrl(artifact.getFile().getAbsolutePath());
+ }
+ }
+
+ private ArtifactResolutionResult resolveArtifact(Artifact filteredArtifact, Artifact providerArtifact)
+ throws ArtifactResolutionException, ArtifactNotFoundException {
+ ArtifactFilter filter = null;
+ if (filteredArtifact != null) {
+ filter =
+ new ExcludesArtifactFilter(Collections.singletonList(filteredArtifact.getGroupId() + ":"
+ + filteredArtifact.getArtifactId()));
+ }
+
+ Artifact originatingArtifact = artifactFactory.createBuildArtifact("dummy", "dummy", "1.0", "jar");
+
+ return artifactResolver.resolveTransitively(Collections.singleton(providerArtifact),
+ originatingArtifact,
+ localRepository,
+ remoteRepositories,
+ metadataSource,
+ filter);
+ }
+
+ private void addArtifact(OSGiSurefireBooter surefireBooter, Artifact surefireArtifact)
+ throws ArtifactNotFoundException, ArtifactResolutionException {
+ ArtifactResolutionResult result = resolveArtifact(null, surefireArtifact);
+
+ for (Iterator i = result.getArtifacts().iterator(); i.hasNext();) {
+ Artifact artifact = (Artifact)i.next();
+
+ getLog().debug("Adding to surefire booter test classpath: " + artifact.getFile().getAbsolutePath());
+
+ surefireBooter.addSurefireBootClassPathUrl(artifact.getFile().getAbsolutePath());
+ }
+ }
+
+ protected void processSystemProperties(boolean setInSystem) {
+ if (systemProperties == null) {
+ systemProperties = new Properties();
+ }
+
+ originalSystemProperties = (Properties)System.getProperties().clone();
+
+ // We used to take all of our system properties and dump them in with the
+ // user specified properties for SUREFIRE-121, causing SUREFIRE-491.
+ // Not gonna do THAT any more... but I'm leaving this code here in case
+ // we need it later when we try to fix SUREFIRE-121 again.
+
+ // Get the properties from the MavenSession instance to make embedded use work correctly
+ Properties userSpecifiedProperties = (Properties)session.getExecutionProperties().clone();
+ userSpecifiedProperties.putAll(systemProperties);
+ //systemProperties = userSpecifiedProperties;
+
+ systemProperties.setProperty("basedir", basedir.getAbsolutePath());
+ systemProperties.setProperty("user.dir", workingDirectory.getAbsolutePath());
+
+ systemProperties.setProperty("localRepository", localRepository.getBasedir());
+
+ if (setInSystem) {
+ // Add all system properties configured by the user
+ Iterator iter = systemProperties.keySet().iterator();
+
+ while (iter.hasNext()) {
+ String key = (String)iter.next();
+
+ String value = systemProperties.getProperty(key);
+
+ System.setProperty(key, value);
+ }
+ }
+ }
+
+ /**
+ * <p>
+ * Adds Reporters that will generate reports with different formatting.
+ * <p>
+ * The Reporter that will be added will be based on the value of the parameter useFile, reportFormat, and
+ * printSummary.
+ *
+ * @param surefireBooter The surefire booter that will run tests.
+ * @param forking
+ */
+ private void addReporters(OSGiSurefireBooter surefireBooter, boolean forking) {
+ Boolean trimStackTrace = Boolean.valueOf(this.trimStackTrace);
+ if (useFile) {
+ if (printSummary) {
+ if (forking) {
+ surefireBooter.addReport(ForkingConsoleReporter.class.getName(), new Object[] {trimStackTrace});
+ } else {
+ surefireBooter.addReport(ConsoleReporter.class.getName(), new Object[] {trimStackTrace});
+ }
+ }
+
+ if (BRIEF_REPORT_FORMAT.equals(reportFormat)) {
+ surefireBooter.addReport(BriefFileReporter.class.getName(), new Object[] {reportsDirectory,
+ trimStackTrace});
+ } else if (PLAIN_REPORT_FORMAT.equals(reportFormat)) {
+ surefireBooter.addReport(FileReporter.class.getName(), new Object[] {reportsDirectory, trimStackTrace});
+ }
+ } else {
+ if (BRIEF_REPORT_FORMAT.equals(reportFormat)) {
+ surefireBooter.addReport(BriefConsoleReporter.class.getName(), new Object[] {trimStackTrace});
+ } else if (PLAIN_REPORT_FORMAT.equals(reportFormat)) {
+ surefireBooter.addReport(DetailedConsoleReporter.class.getName(), new Object[] {trimStackTrace});
+ }
+ }
+
+ if (!disableXmlReport) {
+ surefireBooter.addReport(XMLReporter.class.getName(), new Object[] {reportsDirectory, trimStackTrace});
+ }
+ }
+
+ /**
+ * @return SurefirePlugin Returns the skipExec.
+ */
+ public boolean isSkipExec() {
+ return this.skipTests;
+ }
+
+ /**
+ * @param skipExec the skipExec to set
+ */
+ public void setSkipExec(boolean skipExec) {
+ this.skipTests = skipExec;
+ }
+
+ //TODO remove the part with ToolchainManager lookup once we depend on
+ //3.0.9 (have it as prerequisite). Define as regular component field then.
+ private Toolchain getToolchain() {
+ Toolchain tc = null;
+ try {
+ if (session != null) //session is null in tests..
+ {
+ ToolchainManager toolchainManager =
+ (ToolchainManager)session.getContainer().lookup(ToolchainManager.ROLE);
+ if (toolchainManager != null) {
+ tc = toolchainManager.getToolchainFromBuildContext("jdk", session);
+ }
+ }
+ } catch (ComponentLookupException componentLookupException) {
+ //just ignore, could happen in pre-3.0.9 builds..
+ }
+ return tc;
+ }
+
+ protected Artifact getArtifact(String groupId, String artifactId) throws MojoExecutionException {
+ Artifact artifact;
+ VersionRange vr;
+ try {
+ vr = VersionRange.createFromVersionSpec(project.getVersion());
+ } catch (InvalidVersionSpecificationException e1) {
+ vr = VersionRange.createFromVersion(project.getVersion());
+ }
+ artifact = artifactFactory.createDependencyArtifact(groupId, artifactId, vr, "jar", null, Artifact.SCOPE_TEST);
+
+ try {
+ artifactResolver.resolve(artifact, remoteRepositories, localRepository);
+ } catch (ArtifactResolutionException e) {
+ throw new MojoExecutionException("Unable to resolve artifact.", e);
+ } catch (ArtifactNotFoundException e) {
+ throw new MojoExecutionException("Unable to find artifact.", e);
+ }
+
+ return artifact;
+ }
+
+ private void generateJar(File root, File jar, Manifest mf) throws IOException {
+ getLog().info("Generating " + jar.toString());
+ FileOutputStream fos = new FileOutputStream(jar);
+ JarOutputStream jos = mf != null ? new JarOutputStream(fos, mf) : new JarOutputStream(fos);
+ addDir(jos, root, root);
+ jos.close();
+ }
+
+ /**
+ * Convert the maven version into OSGi version
+ * @param mavenVersion
+ * @return
+ */
+ static String osgiVersion(String mavenVersion) {
+ ArtifactVersion ver = new DefaultArtifactVersion(mavenVersion);
+ String qualifer = ver.getQualifier();
+ if (qualifer != null) {
+ StringBuffer buf = new StringBuffer(qualifer);
+ for (int i = 0; i < buf.length(); i++) {
+ char c = buf.charAt(i);
+ if (Character.isLetterOrDigit(c) || c == '-' || c == '_') {
+ // Keep as-is
+ } else {
+ buf.setCharAt(i, '_');
+ }
+ }
+ qualifer = buf.toString();
+ }
+ Version osgiVersion =
+ new Version(ver.getMajorVersion(), ver.getMinorVersion(), ver.getIncrementalVersion(), qualifer);
+ String version = osgiVersion.toString();
+ return version;
+ }
+
+ private Manifest createMainBundle() throws IOException {
+ File mf = new File(project.getBasedir(), "META-INF/MANIFEST.MF");
+ Manifest manifest = null;
+ if (mf.isFile()) {
+ manifest = new Manifest(new FileInputStream(mf));
+ String bundleName = manifest.getMainAttributes().getValue(BUNDLE_SYMBOLICNAME);
+ if (bundleName != null) {
+ return manifest;
+ }
+ }
+ if (manifest == null) {
+ manifest = new Manifest();
+ }
+ Attributes attributes = manifest.getMainAttributes();
+ attributes.putValue("Manifest-Version", "1.0");
+ attributes.putValue(BUNDLE_MANIFESTVERSION, "2");
+ attributes.putValue(BUNDLE_SYMBOLICNAME, project.getGroupId() + "." + project.getArtifactId());
+ attributes.putValue(BUNDLE_NAME, project.getName());
+ attributes.putValue(BUNDLE_VERSION, osgiVersion(project.getVersion()));
+ attributes.putValue(Constants.DYNAMICIMPORT_PACKAGE, "*");
+ return manifest;
+ }
+
+ private Manifest createTestFragment(Manifest mf) {
+ // Create a manifest
+ Manifest manifest = new Manifest();
+ Attributes attributes = manifest.getMainAttributes();
+ attributes.putValue("Manifest-Version", "1.0");
+ attributes.putValue(BUNDLE_MANIFESTVERSION, "2");
+ String host = mf.getMainAttributes().getValue(BUNDLE_SYMBOLICNAME);
+ int sc = host.indexOf(';');
+ if (sc != -1) {
+ host = host.substring(0, sc);
+ }
+ attributes.putValue(BUNDLE_SYMBOLICNAME, host + ".tests");
+ attributes.putValue(BUNDLE_NAME, mf.getMainAttributes().getValue(BUNDLE_NAME) + " Tests");
+ attributes.putValue(BUNDLE_VERSION, mf.getMainAttributes().getValue(BUNDLE_VERSION));
+ attributes.putValue(Constants.FRAGMENT_HOST, host + ";bundle-version=\""
+ + mf.getMainAttributes().getValue(BUNDLE_VERSION)
+ + "\"");
+ // The main bundle may not have the dependency on JUNIT
+ attributes.putValue(Constants.DYNAMICIMPORT_PACKAGE, "*");
+ return manifest;
+ }
+
+ private void addDir(JarOutputStream jos, File root, File dir) throws IOException, FileNotFoundException {
+ for (File file : dir.listFiles()) {
+ if (file.isDirectory()) {
+ addDir(jos, root, file);
+ } else if (file.isFile()) {
+ // getLog().info(file.toString());
+ String uri = root.toURI().relativize(file.toURI()).toString();
+ if ("META-INF/MANIFEST.MF".equals(uri)) {
+ continue;
+ }
+ ZipEntry entry = new ZipEntry(uri);
+ jos.putNextEntry(entry);
+ byte[] buf = new byte[4096];
+ FileInputStream in = new FileInputStream(file);
+ for (;;) {
+ int len = in.read(buf);
+ if (len > 0) {
+ jos.write(buf, 0, len);
+ } else {
+ break;
+ }
+ }
+ in.close();
+ jos.closeEntry();
+ }
+ }
+ }
+}