001: package org.andromda.maven.plugin.cartridge;
002:
003: import java.io.File;
004: import java.io.IOException;
005:
006: import java.util.Iterator;
007: import java.util.List;
008:
009: import junit.framework.Test;
010: import junit.framework.TestResult;
011:
012: import org.andromda.cartridges.testsuite.CartridgeTest;
013: import org.andromda.core.common.ExceptionUtils;
014: import org.andromda.maven.plugin.AndroMDAMojo;
015: import org.apache.maven.artifact.Artifact;
016: import org.apache.maven.artifact.factory.ArtifactFactory;
017: import org.apache.maven.artifact.repository.ArtifactRepository;
018: import org.apache.maven.model.Dependency;
019: import org.apache.maven.model.Plugin;
020: import org.apache.maven.plugin.AbstractMojo;
021: import org.apache.maven.plugin.MojoExecutionException;
022: import org.apache.maven.plugin.MojoFailureException;
023: import org.apache.maven.project.MavenProject;
024: import org.apache.maven.settings.Settings;
025: import org.codehaus.plexus.archiver.ArchiverException;
026: import org.codehaus.plexus.archiver.UnArchiver;
027: import org.codehaus.plexus.archiver.manager.ArchiverManager;
028: import org.codehaus.plexus.util.FileUtils;
029:
030: /**
031: * Provides the ability to compare cartridge output with existing output.
032: *
033: * @phase test
034: * @goal test
035: * @requiresDependencyResolution test
036: * @description runs AndroMDA Cartridge tests
037: * @author Chad Brandon
038: */
039: public class CartridgeTestMojo extends AbstractMojo {
040: /**
041: * Base directory to which the cartridge test report is written
042: *
043: * @parameter expression="${project.build.directory}/cartridge-test/reports"
044: */
045: private String reportDirectory;
046:
047: /**
048: * Specifies the directory that contains the "actual" output (meaning the output
049: * that was currently generated)
050: * @parameter expression="${project.build.directory}/cartridge-test/actual"
051: * @required
052: */
053: protected String actualDirectory;
054:
055: /**
056: * Specifies the directory that contains the "expected" output.
057: * @parameter expression="${project.build.directory}/cartridge-test/expected"
058: * @required
059: */
060: protected String expectedDirectory;
061:
062: /**
063: * The location of the archive storing the expected output.
064: * @parameter expression="${basedir}/src/test/expected/cartridge-output.zip"
065: * @required
066: */
067: protected String expectedOutputArchive;
068:
069: /**
070: * This is the URI to the AndroMDA configuration file.
071: *
072: * @parameter expression="file:${basedir}/conf/test/andromda.xml"
073: * @required
074: */
075: private String configurationUri;
076:
077: /**
078: * @parameter expression="${project}"
079: * @required
080: * @readonly
081: */
082: private MavenProject project;
083:
084: /**
085: * @parameter expression="${project.build.filters}"
086: */
087: private List propertyFiles;
088:
089: /**
090: * The current user system settings for use in Maven. (allows us to pass the user
091: * settings to the AndroMDA configuration).
092: *
093: * @parameter expression="${settings}"
094: * @required
095: * @readonly
096: */
097: private Settings settings;
098:
099: /**
100: * Defines the extensions of binary files, binary files are checked for presence
101: * and equality, however they aren't compared as strings, like every other file.
102: *
103: * @parameter expression="jpg,jpeg,gif,png,jar,zip"
104: */
105: private String binaryOutputSuffixes;
106:
107: /**
108: * To look up Archiver/UnArchiver implementations
109: *
110: * @parameter expression="${component.org.codehaus.plexus.archiver.manager.ArchiverManager}"
111: * @required
112: */
113: protected ArchiverManager archiverManager;
114:
115: /**
116: * The registered plugin implementations.
117: *
118: * @parameter expression="${project.build.plugins}"
119: * @required
120: * @readonlya
121: */
122: protected List plugins;
123:
124: /**
125: * @parameter expression="${component.org.apache.maven.artifact.factory.ArtifactFactory}"
126: * @required
127: * @readonly
128: */
129: private ArtifactFactory factory;
130:
131: /**
132: * @parameter expression="${localRepository}"
133: * @required
134: * @readonly
135: */
136: protected ArtifactRepository localRepository;
137:
138: /**
139: * Set this to 'true' to bypass cartridge tests entirely. Its use is NOT RECOMMENDED, but quite convenient on occasion.
140: *
141: * @parameter expression="${maven.test.skip}"
142: */
143: protected boolean skip;
144:
145: /**
146: * @see org.apache.maven.plugin.Mojo#execute()
147: */
148: public void execute() throws MojoExecutionException,
149: MojoFailureException {
150: if (!this .skip) {
151: final File expectedOutputArchive = new File(
152: this .expectedOutputArchive);
153: if (!expectedOutputArchive.exists()
154: || !expectedOutputArchive.isFile()) {
155: throw new MojoExecutionException(
156: "The path specifying the expectedOutputArchive '"
157: + this .expectedOutputArchive
158: + "' must be a file");
159: }
160:
161: try {
162: this
163: .getLog()
164: .info(
165: "-----------------------------------------------------------------------------");
166: this
167: .getLog()
168: .info(
169: " A n d r o M D A C a r t r i d g e T e s t S u i t e ");
170: this
171: .getLog()
172: .info(
173: "-----------------------------------------------------------------------------");
174:
175: // - add the cartridge test dependencies (any dependencies of the cartridge test plugin)
176: this .addCartridgeTestDependencies();
177:
178: // - first run AndroMDA with the test configuration
179: final AndroMDAMojo andromdaMojo = new AndroMDAMojo();
180: andromdaMojo.setConfigurationUri(this .configurationUri);
181: andromdaMojo.setProject(this .project);
182: andromdaMojo.setSettings(this .settings);
183: andromdaMojo.setPropertyFiles(this .propertyFiles);
184: andromdaMojo.execute();
185:
186: // - unpack the expected output archive
187: this .unpack(expectedOutputArchive, new File(
188: this .expectedDirectory));
189:
190: final CartridgeTest cartridgeTest = CartridgeTest
191: .instance();
192: cartridgeTest.setActualOutputPath(this .actualDirectory);
193: cartridgeTest
194: .setExpectedOutputPath(this .expectedDirectory);
195: cartridgeTest
196: .setBinarySuffixes(this .binaryOutputSuffixes);
197:
198: final CartridgeTestFormatter formatter = new CartridgeTestFormatter();
199:
200: // - set the report location
201: final File report = new File(this .reportDirectory,
202: this .project.getArtifactId() + ".txt");
203: formatter.setReportFile(report);
204: final TestResult result = new TestResult();
205: result.addListener(formatter);
206: final Test suite = CartridgeTest.suite();
207: formatter.startTestSuite(this .project.getName());
208: suite.run(result);
209: this .getLog().info("");
210: this .getLog().info("Results:");
211: this .getLog().info(formatter.endTestSuite(suite));
212: cartridgeTest.shutdown();
213: if (result.failureCount() > 0
214: || result.errorCount() > 0) {
215: throw new MojoExecutionException(
216: "Test are some test failures");
217: }
218: } catch (final Throwable throwable) {
219: if (throwable instanceof MojoExecutionException) {
220: throw (MojoExecutionException) throwable;
221: }
222: throw new MojoExecutionException(
223: "An error occured while testing cartridge '"
224: + this .project.getArtifactId() + "'",
225: ExceptionUtils.getRootCause(throwable));
226: }
227: } else {
228: this .getLog().info("Skipping cartridge tests");
229: }
230: }
231:
232: /**
233: * Adds any dependencies for the cartridge plugin
234: * to the current dependencies of the project.
235: */
236: private void addCartridgeTestDependencies() {
237: if (this .plugins != null && !this .plugins.isEmpty()) {
238: for (final Iterator iterator = this .plugins.iterator(); iterator
239: .hasNext();) {
240: final Plugin plugin = (Plugin) iterator.next();
241: if (Constants.ARTIFACT_ID
242: .equals(plugin.getArtifactId())) {
243: final List dependencies = plugin.getDependencies();
244: if (dependencies != null) {
245: for (final Iterator dependencyIterator = plugin
246: .getDependencies().iterator(); dependencyIterator
247: .hasNext();) {
248: final Dependency dependency = (Dependency) dependencyIterator
249: .next();
250: dependency.setScope(Artifact.SCOPE_RUNTIME);
251: this .addDependency(dependency);
252: }
253: }
254: }
255: }
256: }
257:
258: // - get all test dependencies, change the scope and add them to them to the dependencies of this
259: // project as runtime scope so that the AndroMDA plugin can see them.
260: for (final Iterator iterator = this .project
261: .getTestDependencies().iterator(); iterator.hasNext();) {
262: final Dependency dependency = (Dependency) iterator.next();
263: dependency.setScope(Artifact.SCOPE_RUNTIME);
264: this .project.getDependencies().add(dependency);
265: }
266: for (final Iterator iterator = this .project.getTestArtifacts()
267: .iterator(); iterator.hasNext();) {
268: final Artifact artifact = (Artifact) iterator.next();
269: artifact.setScope(Artifact.SCOPE_RUNTIME);
270: this .project.getArtifacts().add(artifact);
271: }
272: }
273:
274: /**
275: * Adds a dependency to the current project's dependencies.
276: *
277: * @param dependency
278: */
279: private void addDependency(final Dependency dependency) {
280: if (dependency != null) {
281: final Artifact artifact = this .factory.createArtifact(
282: dependency.getGroupId(),
283: dependency.getArtifactId(),
284: dependency.getVersion(), dependency.getScope(),
285: dependency.getType());
286: final File file = new File(this .localRepository
287: .getBasedir(), this .localRepository
288: .pathOf(artifact));
289: artifact.setFile(file);
290: this .project.getDependencies().add(dependency);
291: this .project.getArtifacts().add(artifact);
292: }
293: }
294:
295: /**
296: * Unpacks the expected archive file to the expected directory
297: *
298: * @param file File to be unpacked.
299: * @param location Location where to put the unpacked files.
300: */
301: protected void unpack(final File file, final File location)
302: throws MojoExecutionException {
303: final String archiveExt = FileUtils.getExtension(
304: file.getAbsolutePath()).toLowerCase();
305: try {
306: final UnArchiver unArchiver;
307: unArchiver = this .archiverManager.getUnArchiver(archiveExt);
308: unArchiver.setSourceFile(file);
309: location.mkdirs();
310: unArchiver.setDestDirectory(location);
311: unArchiver.extract();
312: } catch (Throwable throwable) {
313: if (throwable instanceof IOException
314: || throwable instanceof ArchiverException) {
315: throw new MojoExecutionException(
316: "Error unpacking file: " + file + "to: "
317: + location, throwable);
318: }
319: }
320: }
321: }
|