View Javadoc

1   package org.codehaus.mojo.rspec;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.io.InputStream;
6   import java.io.OutputStream;
7   import java.net.MalformedURLException;
8   import java.util.ArrayList;
9   import java.util.List;
10  import java.util.Properties;
11  
12  import org.apache.maven.plugin.AbstractMojo;
13  import org.apache.maven.plugin.MojoExecutionException;
14  import org.apache.maven.plugin.MojoFailureException;
15  
16  /**
17   * Mojo to run Ruby Spec test
18   * 
19   * @author Michael Ward
20   * @author Mauro Talevi
21   * @goal spec
22   */
23  public class RspecRunnerMojo extends AbstractMojo {
24  
25  	/**
26  	 * The project base directory
27  	 * 
28  	 * @parameter expression="${basedir}"
29  	 * @required
30  	 * @readonly
31  	 */
32  	protected String basedir;
33  
34  	/**
35  	 * The classpath elements of the project being tested.
36  	 * 
37  	 * @parameter expression="${project.testClasspathElements}"
38  	 * @required
39  	 * @readonly
40  	 */
41  	protected List<String> classpathElements;
42  
43  	/**
44  	 * The directory containing the RSpec source files
45  	 * 
46  	 * @parameter
47  	 * @required
48  	 */
49  	protected String sourceDirectory;
50  
51  	/**
52  	 * The directory where the RSpec report will be written to
53  	 * 
54  	 * @parameter
55  	 * @required
56  	 */
57  	protected String outputDirectory;
58  
59  	/**
60  	 * The name of the RSpec report (optional, defaults to "rspec_report.html")
61  	 * 
62  	 * @parameter expression="rspec_report.html"
63  	 */
64  	protected String reportName;
65  
66  	/**
67  	 * The directory where JRuby is installed (optional, defaults to
68  	 * "${user.home}/.jruby")
69  	 * 
70  	 * @parameter expression="${user.home}/.jruby"
71  	 */
72  	protected String jrubyHome;
73  
74  	/**
75  	 * The flag to ignore failures (optional, defaults to "false")
76  	 * 
77  	 * @parameter expression="false"
78  	 */
79  	protected boolean ignoreFailure;
80  
81  	/**
82  	 * The flag to skip tests (optional, defaults to "false")
83  	 * 
84  	 * @parameter expression="false"
85  	 */
86  	protected boolean skipTests;
87  
88  	/**
89  	 * List of system properties to set for the tests.
90  	 * 
91  	 * @parameter
92  	 */
93  	protected Properties systemProperties;
94  
95  	private RSpecScriptFactory rspecScriptFactory = new RSpecScriptFactory();
96  	private ShellScriptFactory shellScriptFactory = new ShellScriptFactory();
97  	
98  	public RspecRunnerMojo() {
99  		
100 	}
101 
102 	public void execute() throws MojoExecutionException, MojoFailureException {
103 		if (skipTests) {
104 			getLog().info("Skipping RSpec tests");
105 			return;
106 		}
107 		getLog().info("Running RSpec tests from " + sourceDirectory);
108 
109 		String reportPath = outputDirectory + "/" + reportName;
110 
111 		initScriptFactory( rspecScriptFactory, reportPath);
112 		initScriptFactory( shellScriptFactory, reportPath);
113 		
114 		try {
115 			rspecScriptFactory.emit();
116 		} catch (Exception e) {
117 			getLog().error( "error emitting .rb", e );
118 		}
119 		try {
120 			shellScriptFactory.emit();
121 		} catch (Exception e) {
122 			getLog().error( "error emitting .sh", e );
123 		}
124 
125 		try {
126 			runScript(rspecScriptFactory.getScript() );
127 		} catch (MalformedURLException e) {
128 			getLog().error( "error running script", e );
129 		}
130 	}
131 	
132 	private void initScriptFactory(ScriptFactory factory, String reportPath) {
133 			factory.setBaseDir(basedir);
134 			factory.setClasspathElements(classpathElements);
135 			factory.setOutputDir(new File(outputDirectory));
136 			factory.setReportPath(reportPath);
137 			factory.setSourceDir(sourceDirectory);
138 			factory.setSystemProperties( systemProperties );
139 	}
140 
141 	private void runScript(String script) {
142 		//getLog().info( "[[\n\n" + script + "\n\n]]" );
143 
144 		List<String> cmdLine = new ArrayList<String>();
145 		cmdLine.add( jrubyHome + "/bin/jruby");
146 
147 		cmdLine.add( "-J-Dbasedir=" + basedir );
148 		for (Object propName : systemProperties.keySet()) {
149 			String propValue = systemProperties.getProperty(propName.toString());
150 			cmdLine.add("-J-D" + propName + "=" + propValue);
151 		}
152 		
153 		//getLog().info( "cmdline [" + cmdLine + "]" );
154 
155 		StringBuilder classpath = new StringBuilder();
156 		boolean first = true;
157 
158 		for (String element : classpathElements) {
159 			if (first) {
160 				first = false;
161 			} else {
162 				classpath.append(":");
163 			}
164 			classpath.append(element);
165 		}
166 
167 		ProcessBuilder builder = new ProcessBuilder(cmdLine);
168 
169 		builder.environment().put("JRUBY_HOME", jrubyHome);
170 		builder.environment().put("CLASSPATH", classpath.toString());
171 
172 		try {
173 			Process process = builder.start();
174 			new InputConsumer(process.getInputStream(), System.out).start();
175 			new InputConsumer(process.getErrorStream(), System.err).start();
176 
177 			OutputStream out = process.getOutputStream();
178 			out.write(script.getBytes());
179 			out.close();
180 
181 			process.waitFor();
182 			System.err.println("exit: " + process.exitValue());
183 		} catch (IOException e) {
184 			getLog().error(e);
185 		} catch (InterruptedException e) {
186 			getLog().error(e);
187 		}
188 	}
189 
190 	private class InputConsumer extends Thread {
191 
192 		private InputStream input;
193 		private OutputStream sink;
194 
195 		public InputConsumer(InputStream input, OutputStream sink) {
196 			this.input = input;
197 			this.sink = sink;
198 		}
199 
200 		public void run() {
201 			byte[] buf = new byte[128];
202 			int len = 0;
203 			try {
204 				while ((len = this.input.read(buf)) >= 0) {
205 					this.sink.write(buf, 0, len);
206 				}
207 			} catch (IOException e) {
208 				e.printStackTrace();
209 			}
210 		}
211 
212 	}
213 
214 }