2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 package org.apache.lucene.util;
21 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.OutputStream;
25 import java.text.NumberFormat;
26 import java.util.logging.LogManager;
28 import junit.framework.AssertionFailedError;
29 import junit.framework.Test;
31 import org.apache.lucene.store.LockReleaseFailedException;
32 import org.apache.lucene.store.NativeFSLockFactory;
33 import org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter;
34 import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
35 import org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner;
36 import org.apache.tools.ant.util.FileUtils;
37 import org.apache.tools.ant.util.StringUtils;
38 import org.junit.Ignore;
41 * Just like BriefJUnitResultFormatter "brief" bundled with ant,
42 * except all formatted text is buffered until the test suite is finished.
43 * At this point, the output is written at once in synchronized fashion.
44 * This way tests can run in parallel without interleaving output.
46 public class LuceneJUnitResultFormatter implements JUnitResultFormatter {
47 private static final double ONE_SECOND = 1000.0;
49 private static final NativeFSLockFactory lockFactory;
51 /** Where to write the log to. */
52 private OutputStream out;
54 /** Formatter for timings. */
55 private NumberFormat numberFormat = NumberFormat.getInstance();
57 /** Output suite has written to System.out */
58 private String systemOutput = null;
60 /** Output suite has written to System.err */
61 private String systemError = null;
63 /** Buffer output until the end of the test */
64 private ByteArrayOutputStream sb; // use a BOS for our mostly ascii-output
66 private static final org.apache.lucene.store.Lock lock;
69 File lockDir = new File(
70 System.getProperty("tests.lockdir", System.getProperty("java.io.tmpdir")),
73 if (!lockDir.exists()) {
74 throw new RuntimeException("Could not make Lock directory:" + lockDir);
77 lockFactory = new NativeFSLockFactory(lockDir);
78 lock = lockFactory.makeLock("junit_lock");
79 } catch (IOException e) {
80 throw new RuntimeException(e);
84 /** Constructor for LuceneJUnitResultFormatter. */
85 public LuceneJUnitResultFormatter() {
89 * Sets the stream the formatter is supposed to write its results to.
90 * @param out the output stream to write to
92 public void setOutput(OutputStream out) {
97 * @see JUnitResultFormatter#setSystemOutput(String)
100 public void setSystemOutput(String out) {
105 * @see JUnitResultFormatter#setSystemError(String)
107 /** {@inheritDoc}. */
108 public void setSystemError(String err) {
114 * The whole testsuite started.
115 * @param suite the test suite
117 public synchronized void startTestSuite(JUnitTest suite) {
119 return; // Quick return - no output do nothing.
121 sb = new ByteArrayOutputStream(); // don't reuse, so its gc'ed
123 LogManager.getLogManager().readConfiguration();
124 } catch (Exception e) {}
125 append("Testsuite: ");
126 append(suite.getName());
127 append(StringUtils.LINE_SEP);
131 * The whole testsuite ended.
132 * @param suite the test suite
134 public synchronized void endTestSuite(JUnitTest suite) {
135 append("Tests run: ");
136 append(suite.runCount());
137 append(", Failures: ");
138 append(suite.failureCount());
139 append(", Errors: ");
140 append(suite.errorCount());
141 append(", Time elapsed: ");
142 append(numberFormat.format(suite.getRunTime() / ONE_SECOND));
144 append(StringUtils.LINE_SEP);
145 append(StringUtils.LINE_SEP);
147 // append the err and output streams to the log
148 if (systemOutput != null && systemOutput.length() > 0) {
149 append("------------- Standard Output ---------------")
150 .append(StringUtils.LINE_SEP)
151 .append(systemOutput)
152 .append("------------- ---------------- ---------------")
153 .append(StringUtils.LINE_SEP);
156 // HACK: junit gives us no way to do this in LuceneTestCase
158 Class<?> clazz = Class.forName(suite.getName());
159 Ignore ignore = clazz.getAnnotation(Ignore.class);
160 if (ignore != null) {
161 if (systemError == null) systemError = "";
162 systemError += "NOTE: Ignoring test class '" + clazz.getSimpleName() + "': "
163 + ignore.value() + StringUtils.LINE_SEP;
165 } catch (ClassNotFoundException e) { /* no problem */ }
168 if (systemError != null && systemError.length() > 0) {
169 append("------------- Standard Error -----------------")
170 .append(StringUtils.LINE_SEP)
172 .append("------------- ---------------- ---------------")
173 .append(StringUtils.LINE_SEP);
185 } catch(LockReleaseFailedException e) {
186 // well lets pretend its released anyway
189 } catch (IOException e) {
190 throw new RuntimeException("unable to write results", e);
192 if (out != System.out && out != System.err) {
193 FileUtils.close(out);
203 public void startTest(Test test) {
210 public void endTest(Test test) {
214 * Interface TestListener for JUnit <= 3.4.
218 * @param t the exception thrown by the test
220 public void addFailure(Test test, Throwable t) {
221 formatError("\tFAILED", test, t);
225 * Interface TestListener for JUnit > 3.4.
229 * @param t the assertion failed by the test
231 public void addFailure(Test test, AssertionFailedError t) {
232 addFailure(test, (Throwable) t);
236 * A test caused an error.
238 * @param error the error thrown by the test
240 public void addError(Test test, Throwable error) {
241 formatError("\tCaused an ERROR", test, error);
245 * Format the test for printing..
247 * @return the formatted testname
249 protected String formatTest(Test test) {
251 return "Null Test: ";
253 return "Testcase: " + test.toString() + ":";
258 * Format an error and print it.
259 * @param type the type of error
260 * @param test the test that failed
261 * @param error the exception that the test threw
263 protected synchronized void formatError(String type, Test test,
269 append(formatTest(test) + type);
270 append(StringUtils.LINE_SEP);
271 append(error.getMessage());
272 append(StringUtils.LINE_SEP);
273 String strace = JUnitTestRunner.getFilteredTrace(error);
275 append(StringUtils.LINE_SEP);
276 append(StringUtils.LINE_SEP);
279 public LuceneJUnitResultFormatter append(String s) {
283 sb.write(s.getBytes()); // intentionally use default charset, its a console.
284 } catch (IOException e) {
285 throw new RuntimeException(e);
290 public LuceneJUnitResultFormatter append(long l) {
291 return append(Long.toString(l));