blob: 517d2ed15f92b9f3b174c42584b5257aab85336c [file] [log] [blame]
/*
* 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.netbeans.modules.testng.ant;
import java.io.File;
import java.util.*;
import org.apache.tools.ant.module.spi.AntEvent;
import org.apache.tools.ant.module.spi.AntLogger;
import org.apache.tools.ant.module.spi.AntSession;
import org.apache.tools.ant.module.spi.TaskStructure;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.modules.gsf.testrunner.api.Report;
import org.netbeans.modules.gsf.testrunner.api.TestSession.SessionType;
import org.netbeans.modules.java.testrunner.ant.utils.AntLoggerUtils;
import org.openide.filesystems.FileUtil;
import org.openide.util.lookup.ServiceProvider;
/**
* Ant logger interested in task "junit",
* dispatching events to instances of the {@link TestNGOutputReader} class.
* There is one <code>TestNGOutputReader</code> instance created per each
* Ant session.
*
* @see TestNGOutputReader
* @see Report
* @author Marian Petras
* @author Lukas Jungmann
*/
@ServiceProvider(service = AntLogger.class)
public final class TestNGAntLogger extends AntLogger {
/** levels of interest for logging (info, warning, error, ...) */
private static final int[] LEVELS_OF_INTEREST = {
AntEvent.LOG_INFO,
AntEvent.LOG_WARN, //test failures
AntEvent.LOG_VERBOSE, //our test listener
AntEvent.LOG_ERR
};
private static final String[] INTERESTING_TASKS = {AntLoggerUtils.TASK_JAVA, AntLoggerUtils.TASK_TESTNG};
private static final String ANT_TEST_RUNNER_CLASS_NAME =
"org.testng.TestNG";//NOI18N
/**
* Default constructor for lookup
*/
public TestNGAntLogger() {
}
@Override
public boolean interestedInSession(AntSession session) {
return true;
}
@Override
public String[] interestedInTargets(AntSession session) {
return AntLogger.ALL_TARGETS;
}
@Override
public String[] interestedInTasks(AntSession session) {
return INTERESTING_TASKS;
}
@Override
public boolean interestedInScript(File script, AntSession session) {
return true;
}
@Override
public int[] interestedInLogLevels(AntSession session) {
return LEVELS_OF_INTEREST;
}
/**
*/
@Override
public void messageLogged(final AntEvent event) {
if (isTestTaskRunning(event)) {
if (event.getLogLevel() != AntEvent.LOG_VERBOSE) {
getOutputReader(event).messageLogged(event);
} else {
/* verbose messages are logged no matter which task produced them */
getOutputReader(event).verboseMessageLogged(event);
}
}
}
/**
*/
private boolean isTestTaskRunning(AntEvent event) {
return AntLoggerUtils.isTestSessionType(getSessionInfo(event.getSession()).getCurrentSessionType());
}
/**
*/
@Override
public void taskStarted(final AntEvent event) {
SessionType sessionType = AntLoggerUtils.detectSessionType(event, AntLoggerUtils.TASK_TESTNG);
if (AntLoggerUtils.isTestSessionType(sessionType)) {
AntSessionInfo sessionInfo = getSessionInfo(event.getSession());
assert !AntLoggerUtils.isTestSessionType(sessionInfo.getCurrentSessionType());
sessionInfo.setTimeOfTestTaskStart(System.currentTimeMillis());
sessionInfo.setCurrentSessionType(sessionType);
if (sessionInfo.getSessionType() == null) {
sessionInfo.setSessionType(sessionType);
}
String suiteName = null;
String logLevel = null;
TaskStructure struct = event.getTaskStructure();
if (AntLoggerUtils.TASK_TESTNG.equals(struct.getName())) {
suiteName = struct.getAttribute("suitename");
logLevel = struct.getAttribute("verbose");
if (logLevel == null) {
logLevel = struct.getAttribute("log");
}
} else if (AntLoggerUtils.TASK_JAVA.equals(struct.getName())) {
TaskStructure[] nestedElems = struct.getChildren();
for (TaskStructure ts : nestedElems) {
if (ts.getName().equals("arg")) { //NOI18N
String a = ts.getAttribute("line");
if (a != null) {
String[] args = event.evaluate(a).split(" ");
int size = args.length;
for (int i = 0; i < size; i++) {
String curr = args[i];
if ("-suitename".equals(curr)) {
suiteName = i + 1 < size ? args[i + 1] : null;
i++;
} else if ("-log".equals(curr) || "-verbose".equals(curr)) {
logLevel = i + 1 < size ? args[i + 1] : null;
i++;
}
}
}
}
}
} else {
assert false : "Unexpeted task " + struct.getName();
}
/*
* Count the test classes in the try-catch block so that
* 'testTaskStarted(...)' is called even if counting fails (throws
* an exception):
*/
//would have to parse all incoming xmls, take includes/excludes
//into accout, dependencies between tests, groups etc
// int testClassCount;
// try {
// testClassCount = TestCounter.getTestClassCount(event);
// } catch (Exception ex) {
// testClassCount = 0;
// Logger.getLogger(TestNGAntLogger.class.getName()).log(Level.SEVERE, null, ex);
// }
if (suiteName != null) {
sessionInfo.setSessionName(event.evaluate(suiteName));
}
boolean offline = false;
if (logLevel != null) {
int lvl;
try {
lvl = Integer.valueOf(event.evaluate(logLevel));
} catch (NumberFormatException nfe) {
lvl = -1;
}
//logging is explicitly turned off by the user, so show only final
//results computed off-line from testng-results.xml file
offline = lvl == 0;
}
getOutputReader(event).testTaskStarted(offline, event);
// getOutputReader(event).testTaskStarted(testClassCount, hasXmlOutput, event);
}
}
/**
*/
@Override
public void taskFinished(final AntEvent event) {
AntSessionInfo sessionInfo = getSessionInfo(event.getSession());
if (AntLoggerUtils.isTestSessionType(sessionInfo.getCurrentSessionType())) {
getOutputReader(event).testTaskFinished();
sessionInfo.setCurrentSessionType(null);
}
}
/**
*/
@Override
public void buildFinished(final AntEvent event) {
AntSession session = event.getSession();
AntSessionInfo sessionInfo = getSessionInfo(session);
if (AntLoggerUtils.isTestSessionType(sessionInfo.getSessionType())) {
getOutputReader(event).buildFinished(event);
}
session.putCustomData(this, null); //forget AntSessionInfo
}
/**
* Retrieve existing or creates a new reader for the given session.
*
* @param session session to return a reader for
* @return output reader for the session
*/
private TestNGOutputReader getOutputReader(final AntEvent event) {
assert AntLoggerUtils.isTestSessionType(getSessionInfo(event.getSession()).getSessionType());
final AntSession session = event.getSession();
final AntSessionInfo sessionInfo = getSessionInfo(session);
TestNGOutputReader outputReader = sessionInfo.outputReader;
if (outputReader == null) {
String projectDir = null;
Project project = null;
try {
projectDir = event.getProperty("work.dir"); //NOI18N
} catch (Exception e) {
}// Maven throws exception for this property
try {
if (projectDir == null) {
projectDir = event.getProperty("basedir"); // NOI18N
}
if ((projectDir != null) && (projectDir.length() != 0)) {
File f = FileUtil.normalizeFile(new File(projectDir));
project = FileOwnerQuery.getOwner(FileUtil.toFileObject(f)); //NOI18N
}
} catch (Exception e) {
}
Properties props = new Properties();
String[] propsOfInterest = {"test.class", "test.methods", "javac.includes", "classname", "methodname", "work.dir", "classpath", "platform.java", "test.includes"};//NOI18N
for(String prop:propsOfInterest) {
String val = event.getProperty(prop);
if (val!=null) {
props.setProperty(prop, val);
}
}
outputReader = new TestNGOutputReader(
session,
sessionInfo,
project,
props);
sessionInfo.outputReader = outputReader;
}
return outputReader;
}
/**
*/
private AntSessionInfo getSessionInfo(final AntSession session) {
Object o = session.getCustomData(this);
assert (o == null) || (o instanceof AntSessionInfo);
AntSessionInfo sessionInfo;
if (o != null) {
sessionInfo = (AntSessionInfo) o;
} else {
sessionInfo = new AntSessionInfo();
session.putCustomData(this, sessionInfo);
}
return sessionInfo;
}
}