Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import hudson.Launcher;
import hudson.Proc;
import org.apache.commons.lang.StringUtils;
import hudson.Util;

import javax.annotation.Nonnull;
import java.io.IOException;
Expand All @@ -27,7 +27,7 @@
int nbMaskedPasswords = 0;

for(String password: passwords) {
if(StringUtils.isNotEmpty(password)) {
if(Util.fixEmpty(password) != null) {

Check warning on line 30 in src/main/java/com/smartbear/jenkins/plugins/testcomplete/CustomDecoratedLauncher.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 30 is not covered by tests
regex.append(Pattern.quote(password));
regex.append('|');
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
import jenkins.tasks.SimpleBuildStep;
import net.sf.json.JSONObject;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import hudson.Util;
import org.jenkinsci.Symbol;
import org.jenkinsci.plugins.plaincredentials.StringCredentials;
import org.kohsuke.stapler.*;
Expand Down Expand Up @@ -517,910 +517,910 @@
}

public boolean usingOldCredentials() {
return ((!StringUtils.isEmpty(getUserName())) || (!StringUtils.isEmpty(getUserPassword().getPlainText()))) && (StringUtils.isEmpty(getCredentialsId()));
return ((Util.fixEmpty(getUserName()) != null) || (Util.fixEmpty(getUserPassword().getPlainText()) != null)) && (Util.fixEmpty(getCredentialsId()) == null);
}

private int fixExitCode(int exitCode, Workspace workspace, TaskListener listener) throws IOException, InterruptedException {
BufferedReader br = null;
int fixedCode = exitCode;

try {
if (workspace.getSlaveExitCodeFilePath().exists()) {
br = new BufferedReader(new InputStreamReader(workspace.getSlaveExitCodeFilePath().read(), Charset.forName(Constants.DEFAULT_CHARSET_NAME)));

try {
String exiCodeString = Optional.ofNullable(br.readLine())
.orElseThrow(() -> new NumberFormatException())
.trim();
if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_ExitCodeRead(), exiCodeString);
}
fixedCode = Integer.parseInt(exiCodeString);
} catch (IOException | NumberFormatException e) {
if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_ExitCodeReadFailed());
}
}
} else {
if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_ExitCodeFileNotExists());
}
}
} finally {
if (br != null) {
br.close();
}
workspace.getSlaveExitCodeFilePath().delete();
}

return fixedCode;
}

@Override
public void perform(@Nonnull Run<?, ?> run,
@Nonnull FilePath filePath,
@Nonnull Launcher launcher,
@Nonnull TaskListener taskListener) throws InterruptedException, IOException {

Computer currentComputer = filePath.toComputer();

try {
performInternal(run, filePath, launcher, taskListener, currentComputer);
} catch (InvalidConfigurationException | CBTException | TagsException | CredentialsNotFoundException e) {
TcLog.error(taskListener, e.getMessage());
run.setResult(Result.FAILURE);
} finally {
busyNodes.release(currentComputer);
}
}

public void performInternal(Run<?, ?> run, FilePath filePath, Launcher launcher, TaskListener listener, Computer currentComputer)
throws IOException, InterruptedException, InvalidConfigurationException, CBTException, TagsException, CredentialsNotFoundException {

final PrintStream logger = listener.getLogger();
logger.println();

EnvVars env = run.getEnvironment(listener);

DEBUG = false;
try {
DEBUG = Boolean.parseBoolean(env.expand("${" + DEBUG_FLAG_NAME + "}"));
} catch (Exception e) {
// Do nothing
}

KEEP_LOGS = false;
try {
KEEP_LOGS = Boolean.parseBoolean(env.expand("${" + KEEP_LOGS_FLAG_NAME + "}"));
} catch (Exception e) {
// Do nothing
}

if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_Enabled());
}

checkParameter(launchType, "launchType", TcInstallation.LaunchType.class, null);
checkParameter(executorType, "executorType", TcInstallation.ExecutorType.class, Constants.ANY_CONSTANT);
checkParameter(actionOnWarnings, "actionOnWarnings", BuildStepAction.class, null);
checkParameter(actionOnErrors, "actionOnErrors", BuildStepAction.class, null);

if (sessionScreenResolution != null && (!sessionScreenResolution.isEmpty()) && ScreenResolution.parseResolution(sessionScreenResolution) == null) {
throw new InvalidConfigurationException(String.format(Messages.TcTestBuilder_InvalidParameterValue(), sessionScreenResolution, "sessionScreenResolution"));
}

String testDisplayName;
try {
testDisplayName = makeDisplayName(run, listener);
} catch (Exception e) {
TcLog.error(listener, Messages.TcTestBuilder_ExceptionOccurred(), e.toString());
TcLog.info(listener, Messages.TcTestBuilder_MarkingBuildAsFailed());
run.setResult(Result.FAILURE);
return;
}

TcLog.info(listener, Messages.TcTestBuilder_TestStartedMessage(), testDisplayName);

if (!Utils.isWindows(launcher.getChannel(), listener)) {
TcLog.error(listener, Messages.TcTestBuilder_NotWindowsOS());
TcLog.info(listener, Messages.TcTestBuilder_MarkingBuildAsFailed());
run.setResult(Result.FAILURE);
return;
}

// Search required TC/TE installation

final TcInstallationsScanner scanner = new TcInstallationsScanner(launcher.getChannel(), listener);
List<TcInstallation> installations = scanner.getInstallations();

StringBuilder msgBuilder = new StringBuilder();
msgBuilder.append(Messages.TcTestBuilder_FoundedInstallations());
for (TcInstallation i : installations) {
msgBuilder.append("\n\t").append(i);
}

TcLog.info(listener, msgBuilder.toString());

if (TcInstallation.ExecutorType.TELite.name().equals(executorType)) {
TcLog.warning(listener, Messages.TcTestBuilder_TELiteIsDeprecatedWarning());
setExecutorType(TcInstallation.ExecutorType.TE.name());
}

final TcInstallation chosenInstallation = scanner.findInstallation(installations, getExecutorType(), getExecutorVersion());

if (chosenInstallation == null) {
TcLog.error(listener, Messages.TcTestBuilder_InstallationNotFound());
TcLog.info(listener, Messages.TcTestBuilder_MarkingBuildAsFailed());
run.setResult(Result.FAILURE);
return;
}

TcLog.info(listener, Messages.TcTestBuilder_ChosenInstallation() + "\n\t" + chosenInstallation);

busyNodes.lock(currentComputer, listener);

// Generating paths
final Workspace workspace;
try {
workspace = new Workspace(run, filePath);
} catch (IOException e) {
TcLog.error(listener, Messages.TcTestBuilder_ExceptionOccurred(), e.toString());
TcLog.info(listener, Messages.TcTestBuilder_MarkingBuildAsFailed());
run.setResult(Result.FAILURE);
return;
}

boolean isJNLPSlave = Optional.ofNullable(filePath)
.map(fpath -> fpath.toComputer())
.map(comp -> !comp.isLaunchSupported())
.orElseGet(() -> false) && !Utils.IsLaunchedAsSystemUser(launcher.getChannel(), listener);


boolean needToUseService = useTCService;

if (needToUseService && isJNLPSlave) {
TcLog.warning(listener, Messages.TcTestBuilder_SlaveConnectedWithJNLP());
needToUseService = false;
}

boolean useSessionCreator = chosenInstallation.hasExtendedCommandLine() && (!needToUseService);

TcLog.info(listener, "Log file: %s", workspace.getMasterLogXFilePath().getName());


// Making the command line
List<String> passwordsToMask = new ArrayList<>();
ArgumentListBuilder args = makeCommandLineArgs(run, launcher, listener, workspace, chosenInstallation, useSessionCreator, passwordsToMask);

if (!isJNLPSlave && !needToUseService) {
TcLog.warning(listener, Messages.TcTestBuilder_SlaveConnectedWithService());
}

if (needToUseService && !isJNLPSlave) {
if (!chosenInstallation.isServiceLaunchingAvailable()) {
TcLog.info(listener, Messages.TcTestBuilder_UnableToLaunchByServiceUnsupportedVersion());
TcLog.info(listener, Messages.TcTestBuilder_MarkingBuildAsFailed());
run.setResult(Result.FAILURE);
return;
} else {
try {
args = prepareServiceCommandLine(run, listener, chosenInstallation, args, env);
} catch (CredentialsNotFoundException e) {
throw e;
} catch (Exception e) {
TcLog.printStackTrace(listener, e);
TcLog.info(listener, Messages.TcTestBuilder_MarkingBuildAsFailed());
run.setResult(Result.FAILURE);
return;
}
}
} else if (useSessionCreator) {
try {
args = prepareSessionCreatorCommandLine(listener, chosenInstallation, args, env);
}
catch (Exception e) {
TcLog.printStackTrace(listener, e);
TcLog.info(listener, Messages.TcTestBuilder_MarkingBuildAsFailed());
run.setResult(Result.FAILURE);
return;
}
}

//Prefilight check, check if project file exists
FilePath projectFile = new FilePath(workspace.getSlaveWorkspacePath(), env.expand(getSuite()));
if(!projectFile.exists() || projectFile.isDirectory()) {
TcLog.error(listener, Messages.TcTestBuilder_UnableToFindProjectFile(), projectFile.getRemote());
run.setResult(Result.FAILURE);
return;
}


// TC/TE launching and data processing
TcReportAction tcReportAction = Optional.ofNullable(filePath)
.map(fpath -> fpath.toComputer())
.map(computer -> computer.getNode())
.map(node -> new TcReportAction(run
, workspace.getLogId()
, testDisplayName
, node.getDisplayName()))
.orElseGet(() -> null);

if(tcReportAction == null)
{
run.setResult(Result.FAILURE);
return;
}

int exitCode = -2;
int fixedExitCode = exitCode;
boolean result = false;

Proc process = null;
try {
TcLog.info(listener, Messages.TcTestBuilder_LaunchingTestRunner());

long realTimeout = getTimeoutValue(null, env);
if (realTimeout != -1) {
realTimeout += Constants.WAITING_AFTER_TIMEOUT_INTERVAL;
if (needToUseService) {
realTimeout += Constants.SERVICE_INTERVAL_DELAY;
}
}

long startTime = Utils.getSystemTime(launcher.getChannel(), listener);
Launcher.ProcStarter processStarter = null;

// need to mask any data
if (passwordsToMask.size() > 0) {
Launcher decoratedLauncher = new CustomDecoratedLauncher(launcher, passwordsToMask);
processStarter = decoratedLauncher.launch().cmds(args).envs(run.getEnvironment(listener)).quiet(true);
} else {
processStarter = launcher.launch().cmds(args).envs(run.getEnvironment(listener));
}

processStarter.readStdout();

process = processStarter.start();
InputStream processStdout = process.getStdout();

if (realTimeout == -1) {
exitCode = process.join();
} else {
exitCode = process.joinWithTimeout(realTimeout, TimeUnit.SECONDS, listener);
}

if (DEBUG && (processStdout != null)) {
String processOutput = IOUtils.toString(processStdout, "UTF-8");
if ((processOutput != null) && (!processOutput.isEmpty())) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_ExecutorOutput() + "\n" + processOutput);
}
}

process = null;

fixedExitCode = fixExitCode(exitCode, workspace, listener);
String exitCodeDescription = getExitCodeDescription(fixedExitCode);

TcLog.info(listener, Messages.TcTestBuilder_ExitCodeMessage(),
exitCodeDescription == null ? fixedExitCode : fixedExitCode + " (" + exitCodeDescription + ")");

if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_FixedExitCodeMessage(), exitCode, fixedExitCode);
}

processFiles(chosenInstallation, run, launcher.getChannel(), listener, workspace, tcReportAction, startTime);

if (fixedExitCode == 0) {
result = true;
} else if (fixedExitCode == 1) {
TcLog.warning(listener, Messages.TcTestBuilder_BuildStepHasWarnings());
if (actionOnWarnings.equals(BuildStepAction.MAKE_UNSTABLE.name())) {
TcLog.info(listener, Messages.TcTestBuilder_MarkingBuildAsUnstable());
run.setResult(Result.UNSTABLE);
result = true;
} else if (actionOnWarnings.equals(BuildStepAction.MAKE_FAILED.name())) {
TcLog.info(listener, Messages.TcTestBuilder_MarkingBuildAsFailed());
run.setResult(Result.FAILURE);
} else {
result = true;
}
} else {
TcLog.warning(listener, Messages.TcTestBuilder_BuildStepHasErrors());
if (actionOnErrors.equals(BuildStepAction.MAKE_UNSTABLE.name())) {
TcLog.info(listener, Messages.TcTestBuilder_MarkingBuildAsUnstable());
run.setResult(Result.UNSTABLE);
} else if (actionOnErrors.equals(BuildStepAction.MAKE_FAILED.name())) {
TcLog.info(listener, Messages.TcTestBuilder_MarkingBuildAsFailed());
run.setResult(Result.FAILURE);
}
}
} catch (InterruptedException e) {
// The build has been aborted. Let Jenkins mark it as ABORTED
throw e;
} catch (Exception e) {
TcLog.error(listener, Messages.TcTestBuilder_ExceptionOccurred(),
e.getCause() == null ? e.toString() : e.getCause().toString());
TcLog.info(listener, Messages.TcTestBuilder_MarkingBuildAsFailed());
run.setResult(Result.FAILURE);
} finally {
if (process != null) {
try {
process.kill();
} catch (Exception e) {
// Do nothing
}
}

tcReportAction.setExitCode(fixedExitCode);
tcReportAction.setResult(result);
String tcLogXFileName = tcReportAction.getTcLogXFileName();
tcReportAction.setStartFailed(tcLogXFileName == null || tcLogXFileName.isEmpty());

TcSummaryAction currentAction = getOrCreateAction(run);
currentAction.addReport(tcReportAction);
if (getPublishJUnitReports()) {
publishResult(run, listener, workspace, tcReportAction);
}
}

TcLog.info(listener, Messages.TcTestBuilder_TestExecutionFinishedMessage(), testDisplayName);
}

private TestResultAction getTestResultAction(Run<?, ?> run) {
return run.getAction(TestResultAction.class);
}

private void publishResult(Run<?, ?> run, TaskListener listener,
Workspace workspace, TcReportAction tcReportAction) throws InterruptedException {

if (tcReportAction.getLogInfo() == null || tcReportAction.getLogInfo().getXML() == null) {
TcLog.warning(listener, Messages.TcTestBuilder_UnableToPublishTestData());
return;
}

OutputStream os = null;

String reportFileName = tcReportAction.getId() + ".xml";
FilePath reportFile = new FilePath(workspace.getMasterLogDirectory(), reportFileName);

if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_JUNIT_PathOnMaster(), reportFile.getRemote());
}

try {
os = reportFile.write();

try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
String xml = tcReportAction.getLogInfo().getXML();
byteArrayOutputStream.write(xml.getBytes("UTF-8"));
byteArrayOutputStream.writeTo(os);
} finally {
os.close();
}

if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_JUNIT_GeneratedSuccessfully());
}

if (KEEP_LOGS) {
FilePath slaveJUnitFilePath = new FilePath(workspace.getSlaveWorkspacePath(), reportFileName);
slaveJUnitFilePath.copyFrom(reportFile);

if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_JUNIT_CopiedToWorkspace(), slaveJUnitFilePath.getRemote());
}
}

synchronized (run) {
TestResultAction testResultAction = getTestResultAction(run);

if (testResultAction == null) {
TestResult testResult = new hudson.tasks.junit.TestResult(true);
testResult.parse(new File(reportFile.getRemote()), null);
testResultAction = new TestResultAction(run, testResult, listener);

if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_JUNIT_ResultCreated() + ' ' +
String.format(Messages.TcTestBuilder_Debug_JUNIT_ResultInfo(),
testResultAction.getFailCount(),
testResultAction.getSkipCount(),
testResultAction.getTotalCount()));
}

run.addAction(testResultAction);
} else {
TestResult testResult = testResultAction.getResult();
testResult.parse(new File(reportFile.getRemote()), null);
testResult.tally();
testResultAction.setResult(testResult, listener);

if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_JUNIT_ResultAppended() + ' ' +
String.format(Messages.TcTestBuilder_Debug_JUNIT_ResultInfo(),
testResultAction.getFailCount(),
testResultAction.getSkipCount(),
testResultAction.getTotalCount()));
}
}
}

} catch (IOException e) {
if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_ExceptionOccurred(), e.getMessage());
}
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
// Do nothing
}
}
try {
if (reportFile.exists() && !KEEP_LOGS) {
if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_JUNIT_ReportDeleted());
}
reportFile.delete();
}
} catch (IOException e) {
// Do nothing
}
}
}

private ArgumentListBuilder prepareServiceCommandLine(Run<?, ?> run, TaskListener listener, TcInstallation chosenInstallation, ArgumentListBuilder baseArgs, EnvVars env) throws Exception {
ArgumentListBuilder resultArgs = new ArgumentListBuilder();

resultArgs.addQuoted(chosenInstallation.getServicePath());

String domain = "";
String userName = "";
String password = "";

if (usingOldCredentials()) {
userName = env.expand(getUserName());
password = env.expand(getUserPassword().getPlainText());
} else {
String credentialsId = env.expand(getCredentialsId());

if (!StringUtils.isEmpty(credentialsId)) {
if (Util.fixEmpty(credentialsId) != null) {
StandardUsernamePasswordCredentials credentials = CredentialsProvider.findCredentialById(credentialsId, StandardUsernamePasswordCredentials.class, run);

if (credentials == null) {
throw new CredentialsNotFoundException(String.format(Messages.TcTestBuilder_CredentialsNotFound(), credentialsId));
}

userName = credentials.getUsername();
password = credentials.getPassword().getPlainText();
}
}

if (!StringUtils.isEmpty(userName)) {
if (Util.fixEmpty(userName) != null) {
if (userName.contains("\\")) {
int pos = userName.lastIndexOf("\\");
domain = userName.substring(0, pos);
userName = userName.substring(pos + 1);
}
}

// check credentials

resultArgs.add(Constants.SERVICE_ARG);

resultArgs.add(Constants.SERVICE_ARG_DOMAIN).addQuoted(domain);
resultArgs.add(Constants.SERVICE_ARG_NAME).addQuoted(userName);
resultArgs.add(Constants.SERVICE_ARG_PASSWORD).addQuoted(Utils.encryptPassword(password), true);

long timeout = getTimeoutValue(null, env);

if (timeout != -1) {
timeout += Constants.SERVICE_INTERVAL_DELAY;
timeout *= 1000 /*ms*/;
}

resultArgs.add(Constants.SERVICE_ARG_TIMEOUT).addQuoted(Long.toString(timeout));

resultArgs.add(Constants.SERVICE_ARG_USE_ACTIVE_SESSION).addQuoted(Boolean.toString(getUseActiveSession()));
resultArgs.add(Constants.SERVICE_ARG_COMMAND_LINE).addQuoted(baseArgs.toStringWithQuote());

if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_SessionScreenResolution(), sessionScreenResolution);
}

String sessionScreenResolutionString = sessionScreenResolution;
if (sessionScreenResolutionString == null || sessionScreenResolutionString.isEmpty()) {
sessionScreenResolutionString = ScreenResolution.getDefaultResolutionString();
}

ScreenResolution resolution = ScreenResolution.parseResolution(sessionScreenResolutionString);
if (resolution != null) {
if (!resolution.equals(ScreenResolution.getDefaultResolution())) {
if (chosenInstallation.isCustomScreenResolutionSupported()) {
if (useActiveSession) {
TcLog.warning(listener, Messages.TcTestBuilder_CustomSessionScreenResolutionCanBeIgnored());
}

resultArgs.add(Constants.SERVICE_ARG_SCREEN_WIDTH).addQuoted(Integer.toString(resolution.getWidth()));
resultArgs.add(Constants.SERVICE_ARG_SCREEN_HEIGHT).addQuoted(Integer.toString(resolution.getHeight()));

} else {
TcLog.warning(listener, Messages.TcTestBuilder_CustomSessionScreenResolutionNotSupported());
}
}
} else {
TcLog.warning(listener, Messages.TcTestBuilder_NotSupportedSessionScreenResolution(), sessionScreenResolution);
}

return resultArgs;
}

private ArgumentListBuilder prepareSessionCreatorCommandLine(TaskListener listener, TcInstallation chosenInstallation, ArgumentListBuilder baseArgs, EnvVars env) throws Exception {
ArgumentListBuilder resultArgs = new ArgumentListBuilder();

resultArgs.addQuoted(chosenInstallation.getSessionCreatorPath());
resultArgs.add(Constants.SESSION_CREATOR_ARG);

if (DEBUG) {
resultArgs.add(Constants.SESSION_CREATOR_ARG_VERBOSE);
}

resultArgs.add(Constants.SESSION_CREATOR_ARG_CMD + baseArgs.toStringWithQuote());

return resultArgs;
}

private void processFiles(TcInstallation installation, Run<?, ?> run, VirtualChannel channel, TaskListener listener, Workspace workspace, TcReportAction testResult, long startTime)
throws IOException, InterruptedException {

// reading error file

BufferedReader br = null;
try {
if (workspace.getSlaveErrorFilePath().exists()) {
br = new BufferedReader(new InputStreamReader(workspace.getSlaveErrorFilePath().read(), Charset.forName(Constants.DEFAULT_CHARSET_NAME)));
String errorString = Optional.ofNullable(br.readLine()).orElseGet(() -> "").trim();
TcLog.warning(listener, Messages.TcTestBuilder_ErrorMessage(), errorString);
testResult.setError(errorString);
}
} finally {
if (br != null) {
br.close();
}

if (!KEEP_LOGS) {
workspace.getSlaveErrorFilePath().delete();
}
}

//copying tclogx file

if (workspace.getSlaveLogXFilePath().exists()) {
try {
workspace.getSlaveLogXFilePath().copyTo(workspace.getMasterLogXFilePath());
String logFileName = workspace.getMasterLogXFilePath().getName();
testResult.setTcLogXFileName(logFileName);
EnvVars env = run.getEnvironment(listener);
String suiteFileName = new FilePath(new File(env.expand(getSuite()))).getBaseName();
boolean errorOnWarnings = BuildStepAction.MAKE_FAILED.name().equals(actionOnWarnings);

ILogParser logParser;
ParserSettings parserSettings = new ParserSettings(new File(workspace.getMasterLogXFilePath().getRemote()),
suiteFileName, env.expand(getProject()), getPublishJUnitReports(), errorOnWarnings);

int timezoneOffset = Utils.getTimezoneOffset(channel, listener);

if (installation.hasNewLogVersion()) {
logParser = new LogParser2(parserSettings, timezoneOffset);
} else {
logParser = new LogParser(parserSettings, timezoneOffset);
}

testResult.setLogInfo(logParser.parse(listener));
} finally {
if (!KEEP_LOGS) {
workspace.getSlaveLogXFilePath().delete();
}
}
}
else {
TcLog.error(listener, Messages.TcTestBuilder_UnableToFindLogFile(),
workspace.getSlaveLogXFilePath().getName());
run.setResult(Result.FAILURE);
testResult.setLogInfo(new TcLogInfo(startTime, 0, 0, 1, 0));
}

//copying htmlx file

if (workspace.getSlaveHtmlXFilePath().exists()) {
try {
workspace.getSlaveHtmlXFilePath().copyTo(workspace.getMasterHtmlXFilePath());
String logFileName = workspace.getMasterHtmlXFilePath().getName();
testResult.setHtmlXFileName(logFileName);
} finally {
if (!KEEP_LOGS) {
workspace.getSlaveHtmlXFilePath().delete();
}
}
} else {
TcLog.warning(listener, Messages.TcTestBuilder_UnableToFindLogFile(),
workspace.getSlaveHtmlXFilePath().getName());
}

//copying mht file

if (getGenerateMHT()) {
if (workspace.getSlaveMHTFilePath().exists()) {
try {
workspace.getSlaveMHTFilePath().copyTo(workspace.getMasterMHTFilePath());
String logFileName = workspace.getMasterMHTFilePath().getName();
testResult.setMhtFileName(logFileName);
} finally {
if (!KEEP_LOGS) {
workspace.getSlaveMHTFilePath().delete();
}
}
} else {
TcLog.warning(listener, Messages.TcTestBuilder_UnableToFindLogFile(),
workspace.getSlaveMHTFilePath().getName());
}
}
}

private String makeDisplayName(Run<?, ?> run, TaskListener listener) throws IOException, InterruptedException {
StringBuilder builder = new StringBuilder();
EnvVars env = run.getEnvironment(listener);

String launchType = getLaunchType();

// always add suite name to test display name
String suiteFileName = new FilePath(new File(env.expand(getSuite()))).getBaseName();
builder.append(suiteFileName);

if (TcInstallation.LaunchType.lcProject.name().equals(launchType)) {
builder.append("/");
builder.append(env.expand(getProject()));
} else if (TcInstallation.LaunchType.lcRoutine.name().equals(launchType)) {
builder.append("/");
builder.append(env.expand(getProject()));
builder.append("/");
builder.append(env.expand(getUnit()));
builder.append("/");
builder.append(env.expand(getRoutine()));
} else if (TcInstallation.LaunchType.lcKdt.name().equals(launchType)) {
builder.append("/");
builder.append(env.expand(getProject()));
builder.append("/KeyWordTests|");
builder.append(env.expand(getTest()));
} else if (TcInstallation.LaunchType.lcTags.name().equals(launchType)) {
builder.append("/");
builder.append(env.expand(getProject()));
builder.append("/Tags|");
builder.append(env.expand(getTags()));
} else if (TcInstallation.LaunchType.lcItem.name().equals(launchType)) {
builder.append("/");
builder.append(env.expand(getProject()));
builder.append("/");
builder.append(env.expand(getTest()));
}

return builder.toString();
}

private String getExitCodeDescription(int exitCode) {
switch (exitCode) {
case -6:
return Messages.ErrorMessages_TcServiceProcessNotAvailable();
case -7:
return Messages.ErrorMessages_TcServiceInvalidArgs();
case -8:
return Messages.ErrorMessages_TcServiceInternalError();
case -9:
return Messages.ErrorMessages_TcServiceInternalError();
case -10:
return Messages.ErrorMessages_TcServiceSessionCreationError();
case -11:
return Messages.ErrorMessages_TcServiceSessionLogOffError();
case -12:
return Messages.ErrorMessages_TcServiceProcessCreationError();
case -13:
return Messages.ErrorMessages_TcServiceTimeout();
case -14:
return Messages.ErrorMessages_TcServiceOldVersion();
default:
return null;
}
}

private long getTimeoutValue(TaskListener listener, EnvVars env) {
if (getUseTimeout()) {
try {
long timeout = Long.parseLong(env.expand(getTimeout()));
if (timeout > 0) {
return timeout;
}
} catch (NumberFormatException e) {
// Do nothing
}
if (listener != null) {
TcLog.warning(listener, Messages.TcTestBuilder_InvalidTimeoutValue(), env.expand(getTimeout()));
}
}
return -1; // infinite
}

private void checkParameter(String value, String parameterName, Class<?> targetEnum, String additionalValue) throws InvalidConfigurationException {
if (value == null) {
throw new InvalidConfigurationException(String.format(Messages.TcTestBuilder_InvalidParameterValue(), "", parameterName));
}

for (Object targetValue : targetEnum.getEnumConstants()) {
if (value.equals(targetValue.toString())) {
return;
}
}

if (value.equals(additionalValue)) {
return;
}

throw new InvalidConfigurationException(String.format(Messages.TcTestBuilder_InvalidParameterValue(), value, parameterName));
}

private void addArg(ArgumentListBuilder args, String value, boolean newFormat) {
if (newFormat) {
args.addQuoted(value);
} else {
args.add(value);
}
}

private ArgumentListBuilder makeCommandLineArgs(Run<?, ?> run,
Launcher launcher,
TaskListener listener,
Workspace workspace,
TcInstallation installation,
boolean useNewCommandLineFormat,
Collection<String> passwordsToMask) throws IOException, InterruptedException, TagsException, CredentialsNotFoundException {
ArgumentListBuilder args = new ArgumentListBuilder();

FilePath execPath = new FilePath(launcher.getChannel(), installation.getExecutorPath());
addArg(args, execPath.getRemote(), useNewCommandLineFormat);

EnvVars env = run.getEnvironment(listener);

addArg(args, new FilePath(workspace.getSlaveWorkspacePath(), env.expand(getSuite())).getRemote(), useNewCommandLineFormat);

args.add(RUN_ARG);

String accessKeyId = env.expand(getAccessKeyId());

if (!StringUtils.isEmpty(accessKeyId)) {
if (Util.fixEmpty(accessKeyId) != null) {
StringCredentials credentials = CredentialsProvider.findCredentialById(accessKeyId, StringCredentials.class, run);

if (credentials == null) {
throw new CredentialsNotFoundException(String.format(Messages.TcTestBuilder_AccessKeyNotFound(), accessKeyId));
}

String accessKey = credentials.getSecret().getPlainText();
args.add(ACCESS_KEY_ARG + accessKey, true);
passwordsToMask.add(accessKey);
}

args.add(SILENT_MODE_ARG);
args.add(FORCE_CONVERSION_ARG);
args.add(NS_ARG);
args.add(EXIT_ARG);

addArg(args, EXPORT_LOG_ARG + workspace.getSlaveLogXFilePath().getRemote(), useNewCommandLineFormat);
addArg(args, EXPORT_LOG_ARG + workspace.getSlaveHtmlXFilePath().getRemote(), useNewCommandLineFormat);
addArg(args, ERROR_LOG_ARG + workspace.getSlaveErrorFilePath(), useNewCommandLineFormat);

if (getGenerateMHT()) {
addArg(args, EXPORT_LOG_ARG + workspace.getSlaveMHTFilePath().getRemote(), useNewCommandLineFormat);
}

if (getUseTimeout()) {
long timeout = getTimeoutValue(listener, env);
if (timeout != -1) {
args.add(TIMEOUT_ARG + timeout);
}
}

if (TcInstallation.LaunchType.lcProject.name().equals(launchType)) {
addArg(args, PROJECT_ARG + env.expand(getProject()), useNewCommandLineFormat);
} else if (TcInstallation.LaunchType.lcRoutine.name().equals(launchType)) {
addArg(args, PROJECT_ARG + env.expand(getProject()), useNewCommandLineFormat);
addArg(args, UNIT_ARG + env.expand(getUnit()), useNewCommandLineFormat);
addArg(args, ROUTINE_ARG + env.expand(getRoutine()), useNewCommandLineFormat);
} else if (TcInstallation.LaunchType.lcKdt.name().equals(launchType)) {
addArg(args, PROJECT_ARG + env.expand(getProject()), useNewCommandLineFormat);
addArg(args, TEST_ARG + "KeyWordTests|" + env.expand(getTest()), useNewCommandLineFormat);
} else if (TcInstallation.LaunchType.lcTags.name().equals(launchType)) {
if (installation.compareVersion("14.20", false) < 0) {
throw new TagsException(Messages.TcTestBuilder_Tags_NotSupportedTCVersion());
}

addArg(args, PROJECT_ARG + env.expand(getProject()), useNewCommandLineFormat);
addArg(args, TAGS_ARG + env.expand(getTags()), useNewCommandLineFormat);
} else if (TcInstallation.LaunchType.lcItem.name().equals(launchType)) {
addArg(args, PROJECT_ARG + env.expand(getProject()), useNewCommandLineFormat);
addArg(args, TEST_ARG + env.expand(getTest()), useNewCommandLineFormat);
}
if (getOnPremiseServerUrl() != null && !getOnPremiseServerUrl().trim().isEmpty()){
addArg(args, ON_PREMISE_SERVER_URL_ARG + env.expand(getOnPremiseServerUrl()), useNewCommandLineFormat);
}

if (installation.getType() == TcInstallation.ExecutorType.TE) {
args.add(NO_LOG_ARG);
}

// Custom arguments
if (useNewCommandLineFormat) {

String[] tokenizedArgs = Util.tokenize(env.expand(getCommandLineArguments()));

for (String arg : tokenizedArgs) {
String escapedCommandLineArgument = arg.replace("\"", "\\\\\\\"");
if (!escapedCommandLineArgument.isEmpty()) {
args.add("\"" + escapedCommandLineArgument + "\"");
}
}
} else {
args.addTokenized(env.expand(getCommandLineArguments()));
}

String version = Utils.getPluginVersionOrNull();
if (version != null) {
args.add(VERSION_ARG + version);
} else {
if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_FailedToDefineSelfVersion());
}
}

if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_OnPremiseServerUrl(), onPremiseServerUrl);
}

if (DEBUG) {
TcLog.debug(listener, Messages.TcTestBuilder_Debug_AdditionalCommandLineArguments(), commandLineArguments);
}

return args;
}

private TcSummaryAction getOrCreateAction(Run<?, ?> run) {
TcSummaryAction currentAction = run.getAction(TcSummaryAction.class);
if (currentAction == null) {
currentAction = new TcSummaryAction(run);
run.addAction(currentAction);
}
return currentAction;
}

@Override
public DescriptorImpl getDescriptor() {
return (DescriptorImpl)super.getDescriptor();
}

@Extension @Symbol("testcompletetest")
public static final class DescriptorImpl extends BuildStepDescriptor<Builder> {

public DescriptorImpl() {
super(TcTestBuilder.class);
load();
}

public String getPluginName() {
return Constants.PLUGIN_NAME;
}

@Override
public Builder newInstance(StaplerRequest req, @Nonnull JSONObject formData) throws FormException {
TcTestBuilder builder = (TcTestBuilder)super.newInstance(req, formData);
if (!StringUtils.isEmpty(builder.getCredentialsId())) {
if (Util.fixEmpty(builder.getCredentialsId()) != null) {

Check warning on line 1423 in src/main/java/com/smartbear/jenkins/plugins/testcomplete/TcTestBuilder.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 520-1423 are not covered by tests
builder.setUserName("");
builder.setUserPassword("");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import com.smartbear.jenkins.plugins.testcomplete.TcLogInfo;
import com.smartbear.jenkins.plugins.testcomplete.Utils;
import hudson.model.TaskListener;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.*;

import javax.xml.stream.*;
Expand Down Expand Up @@ -215,55 +214,55 @@
messages.addAll(LogNodeUtils.getWarningMessages(rootOwnerNodeInfo));
}

writer.writeAttribute("message", StringUtils.join(messages, "\n\n"));
writer.writeAttribute("message", String.join("\n\n", messages));
writer.writeEndElement(); //failure
}
writer.writeEndElement(); //testcase


writer.writeEndElement(); //testsuite
}

writer.writeEndElement(); //testsuites
writer.writeEndDocument();
}

private void processItem(ZipFile logArchive, Node node, String projectName, XMLStreamWriter writer, String name)
throws ParsingException, XMLStreamException {
Node nodeInfo = LogNodeUtils.getRootDocumentNodeFromArchive(logArchive,
LogNodeUtils.getTextProperty(node, "filename"));

if (nodeInfo == null) {
throw new ParsingException("Unable to obtain item node info.");
}

Node logDataRowNode = LogNodeUtils.findNamedNode(LogNodeUtils.findNamedNode(nodeInfo, "log data"), "row0");
if (logDataRowNode == null) {
throw new ParsingException("Unable to obtain log data->row0 node for item with name '" + name + "'.");
}

writer.writeStartElement("testcase");
writer.writeAttribute("name", name);
writer.writeAttribute("classname", context.getSuite() + "." + projectName);

long startTime = Utils.safeConvertDate(LogNodeUtils.getTextProperty(logDataRowNode, "start time"));
long endTime = Utils.safeConvertDate(LogNodeUtils.getTextProperty(logDataRowNode, "end time"));
long duration = endTime - startTime > 0 ? endTime - startTime : 0;

writer.writeAttribute("time", Double.toString(duration / 1000f));

if (checkFail(LogNodeUtils.getTextProperty(node, "status"))) {

Node testDetailsNode = LogNodeUtils.getRootDocumentNodeFromArchive(logArchive,
LogNodeUtils.getTextProperty(logDataRowNode, "details"));
writer.writeStartElement("failure");

List<String> messages = LogNodeUtils.getErrorMessages(testDetailsNode);
if (context.errorOnWarnings()) {
messages.addAll(LogNodeUtils.getWarningMessages(testDetailsNode));
}

writer.writeAttribute("message", StringUtils.join(messages, "\n\n"));
writer.writeAttribute("message", String.join("\n\n", messages));

Check warning on line 265 in src/main/java/com/smartbear/jenkins/plugins/testcomplete/parser/LogParser.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 217-265 are not covered by tests
writer.writeEndElement(); //failure
}
writer.writeEndElement(); //testcase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import com.smartbear.jenkins.plugins.testcomplete.TcLogInfo;
import com.smartbear.jenkins.plugins.testcomplete.Utils;
import hudson.model.TaskListener;
import org.apache.commons.lang.StringUtils;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

Expand Down Expand Up @@ -165,87 +164,87 @@
messages.addAll(LogNodeUtils.getWarningMessages(rootOwnerNodeInfo));
}

writer.writeAttribute("message", StringUtils.join(messages, "\n\n"));
writer.writeAttribute("message", String.join("\n\n", messages));
writer.writeEndElement(); //failure
}

writer.writeEndElement(); //testcase
writer.writeEndElement(); //testsuite
writer.writeEndElement(); //testsuites
writer.writeEndDocument();
}

private void convertSummaryToXML(Node summaryNode, XMLStreamWriter writer) throws ParsingException, XMLStreamException {

writer.writeStartDocument("utf-8", "1.0");
writer.writeStartElement("testsuites");

Node projectsNode = LogNodeUtils.findNamedNode(summaryNode, "projects");

if (projectsNode == null) {
throw new ParsingException(UNEXPECTED_LOG_FORMAT);
}

List<Node> projectNodes = LogNodeUtils.findChildNodes(projectsNode);

for (Node projectNode : projectNodes) {
String failedTests = LogNodeUtils.getTextProperty(projectNode, "failedtests");
if (failedTests == null) {
failedTests = Integer.toString(0);
}

String testProjectName = LogNodeUtils.getTextProperty(projectNode, "name");
String testStartTime = LogNodeUtils.getTextProperty(projectNode, "starttime");
Node testsNode = LogNodeUtils.findNamedNode(projectNode, "tests");

if (testsNode == null) {
throw new ParsingException(UNEXPECTED_LOG_FORMAT);
}

List<Node> testNodes = LogNodeUtils.findChildNodes(testsNode);

String projectDurationMS = LogNodeUtils.getTextProperty(projectNode, "duration");
String projectDuration = Double.toString(Integer.parseInt(projectDurationMS) / 1000f);

writer.writeStartElement("testsuite");
writer.writeAttribute("name", testProjectName);
writer.writeAttribute("time", projectDuration);

writer.writeAttribute("failures", failedTests);
writer.writeAttribute("tests", Integer.toString(testNodes.size()));
writer.writeAttribute("timestamp", LogNodeUtils.startTimeToTimestamp(testStartTime));

for (Node testNode : testNodes) {
String testName = LogNodeUtils.getTextProperty(testNode, "name");

writer.writeStartElement("testcase");
writer.writeAttribute("name", testName);
writer.writeAttribute("classname", context.getSuite() + "." + testProjectName);

String testDurationMS = LogNodeUtils.getTextProperty(testNode, "duration");
String testDuration = Double.toString(Integer.parseInt(testDurationMS) / 1000f);

writer.writeAttribute("time", testDuration);

String testCaseStatus = LogNodeUtils.getTextProperty(testNode, "status");

if (checkIncomplete(testCaseStatus)) {
writer.writeStartElement("skipped");
writer.writeEndElement(); //skipped
} else if (checkFail(testCaseStatus)) {
writer.writeStartElement("failure");

List<String> messages = new ArrayList<>();

List<String> errors = LogNodeUtils.findChildMessages(testNode, "errors", "error");
messages.addAll(errors);

if (context.errorOnWarnings()) {
List<String> warnings = LogNodeUtils.findChildMessages(testNode, "warnings", "warning");
messages.addAll(warnings);
}

writer.writeAttribute("message", StringUtils.join(messages, "\n\n"));
writer.writeAttribute("message", String.join("\n\n", messages));

Check warning on line 247 in src/main/java/com/smartbear/jenkins/plugins/testcomplete/parser/LogParser2.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 167-247 are not covered by tests
writer.writeEndElement(); //failure
}

Expand Down