Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speedup gradle test output XML processing #508

Merged
merged 8 commits into from
Feb 3, 2017
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@
import com.intellij.execution.testframework.sm.runner.states.TestStateInfo;
import com.intellij.execution.testframework.sm.runner.ui.SMRootTestProxyFormatter;
import com.intellij.execution.testframework.sm.runner.ui.TestTreeRenderer;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.execution.ExternalSystemExecutionConsoleManager;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ExternalProjectInfo;
Expand All @@ -46,20 +44,17 @@
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.action.GradleRerunFailedTestsAction;
import org.jetbrains.plugins.gradle.execution.test.runner.events.*;
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverUtil;
import org.jetbrains.plugins.gradle.service.resolve.GradleCommonClassNames;
import org.jetbrains.plugins.gradle.util.GradleBundle;
import org.jetbrains.plugins.gradle.util.GradleConstants;
import org.jetbrains.plugins.gradle.util.XmlXpathHelper;

/**
* @author Vladislav.Soroka
* @since 2/18/14
*/
public class GradleTestsExecutionConsoleManager
implements ExternalSystemExecutionConsoleManager<ExternalSystemRunConfiguration, GradleTestsExecutionConsole, ProcessHandler> {
private static final Logger LOG = Logger.getInstance(GradleTestsExecutionConsoleManager.class);

@NotNull
@Override
Expand Down Expand Up @@ -125,61 +120,7 @@ public void onOutput(@NotNull GradleTestsExecutionConsole executionConsole,
@NotNull ProcessHandler processHandler,
@NotNull String text,
@NotNull Key processOutputType) {
final StringBuilder consoleBuffer = executionConsole.getBuffer();
if (StringUtil.endsWith(text, "<ijLogEol/>\n")) {
consoleBuffer.append(StringUtil.trimEnd(text, "<ijLogEol/>\n")).append('\n');
return;
}
else {
consoleBuffer.append(text);
}

String trimmedText = consoleBuffer.toString().trim();
consoleBuffer.setLength(0);

if (!StringUtil.startsWith(trimmedText, "<ijLog>") || !StringUtil.endsWith(trimmedText, "</ijLog>")) {
if (text.trim().isEmpty()) return;
executionConsole.print(text, ConsoleViewContentType.getConsoleViewType(processOutputType));
return;
}

try {
final XmlXpathHelper xml = new XmlXpathHelper(trimmedText);

final TestEventType eventType = TestEventType.fromValue(xml.queryXml("/ijLog/event/@type"));
TestEvent testEvent = null;
switch (eventType) {
case CONFIGURATION_ERROR:
testEvent = new ConfigurationErrorEvent(executionConsole);
break;
case REPORT_LOCATION:
testEvent = new ReportLocationEvent(executionConsole);
break;
case BEFORE_TEST:
testEvent = new BeforeTestEvent(executionConsole);
break;
case ON_OUTPUT:
testEvent = new OnOutputEvent(executionConsole);
break;
case AFTER_TEST:
testEvent = new AfterTestEvent(executionConsole);
break;
case BEFORE_SUITE:
testEvent = new BeforeSuiteEvent(executionConsole);
break;
case AFTER_SUITE:
testEvent = new AfterSuiteEvent(executionConsole);
break;
case UNKNOWN_EVENT:
break;
}
if (testEvent != null) {
testEvent.process(xml);
}
}
catch (XmlXpathHelper.XmlParserException e) {
LOG.error("Gradle test events parser error", e);
}
GradleTestsExecutionConsoleOutputProcessor.onOutput(executionConsole, text, processOutputType);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed 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.jetbrains.plugins.gradle.execution.test.runner;

import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.execution.test.runner.events.*;
import org.jetbrains.plugins.gradle.execution.test.runner.events.TestEventXmlXPathView;

/**
* Created by eugene.petrenko@gmail.com
*/
public class GradleTestsExecutionConsoleOutputProcessor {
private static final Logger LOG = Logger.getInstance(GradleTestsExecutionConsoleOutputProcessor.class);

public static void onOutput(@NotNull GradleTestsExecutionConsole executionConsole,
@NotNull String text,
@NotNull Key processOutputType) {
final StringBuilder consoleBuffer = executionConsole.getBuffer();
if (StringUtil.endsWith(text, "<ijLogEol/>\n")) {
consoleBuffer.append(StringUtil.trimEnd(text, "<ijLogEol/>\n")).append('\n');
return;
}
else {
consoleBuffer.append(text);
}

String trimmedText = consoleBuffer.toString().trim();
consoleBuffer.setLength(0);

if (!StringUtil.startsWith(trimmedText, "<ijLog>") || !StringUtil.endsWith(trimmedText, "</ijLog>")) {
if (text.trim().isEmpty()) return;
executionConsole.print(text, ConsoleViewContentType.getConsoleViewType(processOutputType));
return;
}

try {
final TestEventXmlView xml = new TestEventXPPXmlView(trimmedText);

final TestEventType eventType = TestEventType.fromValue(xml.getTestEventType());
TestEvent testEvent = null;
switch (eventType) {
case CONFIGURATION_ERROR:
testEvent = new ConfigurationErrorEvent(executionConsole);
break;
case REPORT_LOCATION:
testEvent = new ReportLocationEvent(executionConsole);
break;
case BEFORE_TEST:
testEvent = new BeforeTestEvent(executionConsole);
break;
case ON_OUTPUT:
testEvent = new OnOutputEvent(executionConsole);
break;
case AFTER_TEST:
testEvent = new AfterTestEvent(executionConsole);
break;
case BEFORE_SUITE:
testEvent = new BeforeSuiteEvent(executionConsole);
break;
case AFTER_SUITE:
testEvent = new AfterSuiteEvent(executionConsole);
break;
case UNKNOWN_EVENT:
break;
}
if (testEvent != null) {
testEvent.process(xml);
}
}
catch (TestEventXmlXPathView.XmlParserException e) {
LOG.error("Gradle test events parser error", e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.jetbrains.plugins.gradle.execution.GradleRunnerUtil;
import org.jetbrains.plugins.gradle.execution.test.runner.GradleConsoleProperties;
import org.jetbrains.plugins.gradle.execution.test.runner.GradleTestsExecutionConsole;
import org.jetbrains.plugins.gradle.util.XmlXpathHelper;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
Expand Down Expand Up @@ -61,26 +60,6 @@ protected String findLocationUrl(@Nullable String name, @NotNull String fqClassN
return GradleRunnerUtil.getTestLocationUrl(name, fqClassName);
}

protected String getTestName(@NotNull XmlXpathHelper eventXml) throws XmlXpathHelper.XmlParserException {
return eventXml.queryXml("/ijLog/event/test/descriptor/@name");
}

protected String getParentTestId(@NotNull XmlXpathHelper eventXml) throws XmlXpathHelper.XmlParserException {
return eventXml.queryXml("/ijLog/event/test/@parentId");
}

protected String getTestId(@NotNull XmlXpathHelper eventXml) throws XmlXpathHelper.XmlParserException {
return eventXml.queryXml("/ijLog/event/test/@id");
}

protected String getTestClassName(@NotNull XmlXpathHelper eventXml) throws XmlXpathHelper.XmlParserException {
return eventXml.queryXml("/ijLog/event/test/descriptor/@className");
}

protected TestEventResult getTestEventResultType(@NotNull XmlXpathHelper eventXml) throws XmlXpathHelper.XmlParserException {
return TestEventResult.fromValue(eventXml.queryXml("/ijLog/event/test/result/@resultType"));
}

protected void addToInvokeLater(final Runnable runnable) {
ExternalSystemApiUtil.addToInvokeLater(runnable);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
package org.jetbrains.plugins.gradle.execution.test.runner.events;

import com.intellij.execution.testframework.sm.runner.SMTestProxy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.execution.test.runner.GradleTestsExecutionConsole;
import org.jetbrains.plugins.gradle.util.XmlXpathHelper;

/**
* @author Vladislav.Soroka
Expand All @@ -29,9 +29,9 @@ public AfterSuiteEvent(GradleTestsExecutionConsole executionConsole) {
}

@Override
public void process(XmlXpathHelper eventXml) throws XmlXpathHelper.XmlParserException {
final String testId = getTestId(eventXml);
final TestEventResult result = getTestEventResultType(eventXml);
public void process(@NotNull TestEventXmlView eventXml) throws TestEventXmlView.XmlParserException {
final String testId = eventXml.getTestId();
final TestEventResult result = TestEventResult.fromValue(eventXml.getTestEventResultType());

addToInvokeLater(() -> {
final SMTestProxy testProxy = findTestProxy(testId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.execution.test.runner.GradleTestsExecutionConsole;
import org.jetbrains.plugins.gradle.util.XmlXpathHelper;

import java.util.ArrayList;
import java.util.regex.Matcher;
Expand All @@ -37,14 +37,14 @@ public AfterTestEvent(GradleTestsExecutionConsole executionConsole) {
}

@Override
public void process(XmlXpathHelper eventXml) throws XmlXpathHelper.XmlParserException {
public void process(@NotNull final TestEventXmlView eventXml) throws TestEventXmlView.XmlParserException {

final String testId = getTestId(eventXml);
final String testId = eventXml.getTestId();

final String startTime = eventXml.queryXml("/ijLog/event/test/result/@startTime");
final String endTime = eventXml.queryXml("/ijLog/event/test/result/@endTime");
final String exceptionMsg = decode(eventXml.queryXml("/ijLog/event/test/result/errorMsg"));
final String stackTrace = decode(eventXml.queryXml("/ijLog/event/test/result/stackTrace"));
final String startTime = eventXml.getEventTestResultStartTime();
final String endTime = eventXml.getEventTestResultEndTime();
final String exceptionMsg = decode(eventXml.getEventTestResultErrorMsg());
final String stackTrace = decode(eventXml.getEventTestResultStackTrace());

final SMTestProxy testProxy = findTestProxy(testId);
if (testProxy == null) return;
Expand All @@ -56,20 +56,20 @@ public void process(XmlXpathHelper eventXml) throws XmlXpathHelper.XmlParserExce
}

final CompositeRunnable runInEdt = new CompositeRunnable();
final TestEventResult result = getTestEventResultType(eventXml);
final TestEventResult result = TestEventResult.fromValue(eventXml.getTestEventResultType());
switch (result) {
case SUCCESS:
runInEdt.add(testProxy::setFinished);
break;
case FAILURE:
final String failureType = eventXml.queryXml("/ijLog/event/test/result/failureType");
final String failureType = eventXml.getEventTestResultFailureType();
if ("comparison".equals(failureType)) {
String actualText = decode(eventXml.queryXml("/ijLog/event/test/result/actual"));
String expectedText = decode(eventXml.queryXml("/ijLog/event/test/result/expected"));
String actualText = decode(eventXml.getEventTestResultActual());
String expectedText = decode(eventXml.getEventTestResultExpected());
final Condition<String> emptyString = StringUtil::isEmpty;
String filePath = ObjectUtils.nullizeByCondition(decode(eventXml.queryXml("/ijLog/event/test/result/filePath")), emptyString);
String filePath = ObjectUtils.nullizeByCondition(decode(eventXml.getEventTestResultFilePath()), emptyString);
String actualFilePath = ObjectUtils.nullizeByCondition(
decode(eventXml.queryXml("/ijLog/event/test/result/actualFilePath")), emptyString);
decode(eventXml.getEventTestResultActualFilePath()), emptyString);
testProxy.setTestComparisonFailed(exceptionMsg, stackTrace, actualText, expectedText, filePath, actualFilePath);
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
package org.jetbrains.plugins.gradle.execution.test.runner.events;

import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.execution.test.runner.GradleSMTestProxy;
import org.jetbrains.plugins.gradle.execution.test.runner.GradleTestsExecutionConsole;
import org.jetbrains.plugins.gradle.util.XmlXpathHelper;

/**
* @author Vladislav.Soroka
Expand All @@ -30,11 +30,11 @@ public BeforeSuiteEvent(GradleTestsExecutionConsole executionConsole) {
}

@Override
public void process(XmlXpathHelper eventXml) throws XmlXpathHelper.XmlParserException {
final String testId = getTestId(eventXml);
final String parentTestId = getParentTestId(eventXml);
final String name = getTestName(eventXml);
final String fqClassName = getTestClassName(eventXml);
public void process(@NotNull final TestEventXmlView eventXml) throws TestEventXmlView.XmlParserException {
final String testId = eventXml.getTestId();
final String parentTestId = eventXml.getTestParentId();
final String name = eventXml.getTestName();
final String fqClassName = eventXml.getTestClassName();

if (StringUtil.isEmpty(parentTestId)) {
registerTestProxy(testId, getResultsViewer().getTestsRootNode());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
import com.intellij.execution.testframework.sm.runner.SMTestProxy;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.execution.test.runner.GradleSMTestProxy;
import org.jetbrains.plugins.gradle.execution.test.runner.GradleTestsExecutionConsole;
import org.jetbrains.plugins.gradle.util.XmlXpathHelper;

import java.util.List;

Expand All @@ -35,11 +35,11 @@ public BeforeTestEvent(GradleTestsExecutionConsole executionConsole) {
}

@Override
public void process(XmlXpathHelper eventXml) throws XmlXpathHelper.XmlParserException {
final String testId = getTestId(eventXml);
final String parentTestId = getParentTestId(eventXml);
final String name = getTestName(eventXml);
final String fqClassName = getTestClassName(eventXml);
public void process(@NotNull final TestEventXmlView eventXml) throws TestEventXmlView.XmlParserException {
final String testId = eventXml.getTestId();
final String parentTestId = eventXml.getTestParentId();
final String name = eventXml.getTestName();
final String fqClassName = eventXml.getTestClassName();

String locationUrl = findLocationUrl(name, fqClassName);
final GradleSMTestProxy testProxy = new GradleSMTestProxy(name, false, locationUrl, fqClassName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import org.jetbrains.plugins.gradle.execution.test.runner.GradleTestsExecutionConsole;
import org.jetbrains.plugins.gradle.service.project.GradleNotification;
import org.jetbrains.plugins.gradle.util.GradleConstants;
import org.jetbrains.plugins.gradle.util.XmlXpathHelper;

import javax.swing.event.HyperlinkEvent;

Expand All @@ -44,12 +43,10 @@ public ConfigurationErrorEvent(GradleTestsExecutionConsole executionConsole) {
}

@Override
public void process(XmlXpathHelper xml) throws XmlXpathHelper.XmlParserException {
final String errorTitle = xml.queryXml("/ijLog/event/title");
assert errorTitle != null;
final String configurationErrorMsg = xml.queryXml("/ijLog/event/message");
assert configurationErrorMsg != null;
final boolean openSettings = Boolean.valueOf(xml.queryXml("/ijLog/event/@openSettings"));
public void process(@NotNull final TestEventXmlView xml) throws TestEventXmlView.XmlParserException {
final String errorTitle = xml.getEventTitle();
final String configurationErrorMsg = xml.getEventMessage();
final boolean openSettings = xml.isEventOpenSettings();
final Project project = getProject();
assert project != null;
final String message =
Expand Down
Loading