io.sealights.onpremise.agents.plugin.surefire.PluginsHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sealights-maven-plugin
Show all versions of sealights-maven-plugin
A maven plugin to run java agents.
The newest version!
package io.sealights.onpremise.agents.plugin.surefire;
import static io.sealights.onpremise.agents.infra.constants.Constants.SPACE;
import static io.sealights.onpremise.agents.plugin.jacoco.JacocoPluginHandler.JACOCO_ARTIFACT_ID;
import static io.sealights.onpremise.agents.plugin.surefire.PluginCfgValidator.SUREFIRE_OR_FAILSAFE_NOT_FOUND;
import static io.sealights.onpremise.agents.plugin.surefire.PluginConfiguration.ARG_LINE;
import static io.sealights.onpremise.agents.plugin.surefire.PluginConfiguration.FAILSAFE_ARTIFACT_ID;
import static io.sealights.onpremise.agents.plugin.surefire.PluginConfiguration.SUREFIRE_ARTIFACT_ID;
import io.sealights.onpremise.agents.plugin.LogUtil;
import io.sealights.onpremise.agents.plugin.jacoco.JacocoPluginConfiguration;
import io.sealights.onpremise.agents.plugin.jacoco.JacocoPluginHandler;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import lombok.Getter;
import org.apache.maven.model.Plugin;
import org.apache.maven.project.MavenProject;
import io.sealights.onpremise.agents.infra.constants.Constants;
import io.sealights.onpremise.agents.infra.constants.SLProperties;
import io.sealights.onpremise.agents.infra.utils.StringUtils;
import io.sealights.onpremise.agents.plugin.SeaLightsMojo;
import io.sealights.plugins.engine.lifecycle.BuildLifeCycle;
import lombok.Setter;
import lombok.experimental.UtilityClass;
import org.slf4j.Logger;
/**
* Encapsulates surefire/failsafe configuration discovery and handling
*
* @author AlaSchneider
*
*/
public class PluginsHandler {
public static final String SL_TEST_LISTENER = "sl-test-listener";
public static final String JAVA_TEST_LISTENER = "java-test-listener";
public static final String DEV_SL_TEST_LISTENER = "java-agent-bootstrapper-1.0.0-SNAPSHOT";
public final static String SEALIGHTS_ARG_LINE = "sealightsArgLine";
public final static String SEALIGHTS_DISABLED = SLProperties.toJvmAgr(SLProperties.ENABLED, Constants.FALSE);
@Setter
private MavenProject project;
@Setter
private Logger logger;
private boolean pluginsDiscovered;
private JacocoPluginConfiguration jacocoPluginConfiguration;
@Getter // ugly - for testing
private PluginCfgValidator surefireValidator;
@Getter // ugly - for testing
private PluginCfgValidator failsafeValidator;
@Getter // ugly - for testing
private Properties projectProperties;
private String initialArgLinePropertyValue;
public PluginsHandler(MavenProject project, Logger logger) {
setProject(project);
setLogger(logger);
project.getPlugin("");
surefireValidator = PluginCfgValidator.createSurefireCfgValidator();
failsafeValidator = PluginCfgValidator.createFailsafeCfgValidator();
pluginsDiscovered = false;
projectProperties = project.getProperties();
}
public void detectConfigurations() {
if (pluginsDiscovered) {
return;
}
lookForPlugins(project.getBuildPlugins());
if (!bothPluginsFound() && project.getPluginManagement() != null) {
// If surefire/failsafe are not defined in build plugins, try the PluginManagement
lookForPlugins(project.getPluginManagement().getPlugins());
}
pluginsDiscovered = true;
logger.info("Done discovery of surefire and failsafe plugins: surefire {}, failsafe {}",
buildFoundString(isSurefireExists()), buildFoundString(isFailsafeExists()));
}
public void updateProperties(String slArgument, String token, boolean withSealights) {
logger.info("Updating the properties: '{}', '{}'", LogUtil.maskToken(slArgument), withSealights);
notifyConfiguration();
handleArgLineProperty(slArgument, withSealights);
projectProperties.setProperty(SEALIGHTS_ARG_LINE, slArgument);
PluginCfgLogger.logPluginSettings(
logger,
project.getProperties(),
surefireValidator.getConfiguration(),
failsafeValidator.getConfiguration(),
token,
withSealights);
}
public boolean isSurefireExists() {
return surefireValidator.isPluginExists();
}
public boolean isFailsafeExists() {
return failsafeValidator.isPluginExists();
}
public boolean isValidConfiguration() {
return surefireValidator.isValidConfiguration() && failsafeValidator.isValidConfiguration();
}
public void notifyConfiguration() {
StringBuilder notifMessageBuilder = new StringBuilder();
notifMessageBuilder.append("module:").append(project.getName()).append(", ");
boolean surefireNotified = logAndNotifyPluginConfiguration(surefireValidator, notifMessageBuilder, false);
boolean failsafeNotified = logAndNotifyPluginConfiguration(failsafeValidator, notifMessageBuilder, surefireNotified);
if (!SeaLightsMojo.POM_PACKAGING_VALUE.equals(project.getPackaging()) && !surefireNotified && !failsafeNotified) {
BuildLifeCycle.notifyWarning(SUREFIRE_OR_FAILSAFE_NOT_FOUND);
logger.warn(SUREFIRE_OR_FAILSAFE_NOT_FOUND);
}
else {
BuildLifeCycle.notifyInfo(notifMessageBuilder.toString());
}
}
String getSurefireArgLine() {
return surefireValidator.getConfiguration().getArgLine();
}
String getFailsafeArgLine() {
return failsafeValidator.getConfiguration().getArgLine();
}
private void lookForPlugins(List plugins) {
Plugin surefirePlugin = null;
Plugin failsafePlugin = null;
Plugin jacocoPlugin = null;
for (Plugin plugin : plugins) {
if (SUREFIRE_ARTIFACT_ID.equals(plugin.getArtifactId()) && !surefireValidator.isPluginExists()) {
surefirePlugin = plugin;
}
if (FAILSAFE_ARTIFACT_ID.equals(plugin.getArtifactId()) && !failsafeValidator.isPluginExists()) {
failsafePlugin = plugin;
}
if(JACOCO_ARTIFACT_ID.equals(plugin.getArtifactId())){
jacocoPlugin = plugin;
}
}
if (jacocoPlugin != null) {
jacocoPluginConfiguration = JacocoPluginHandler.parse(jacocoPlugin);
}
if (surefirePlugin != null) {
surefireValidator.fillAndValidateConfiguration(surefirePlugin, jacocoPluginConfiguration);
}
if (failsafePlugin != null) {
failsafeValidator.fillAndValidateConfiguration(failsafePlugin, jacocoPluginConfiguration);
}
}
private boolean bothPluginsFound() {
return isSurefireExists() && isFailsafeExists();
}
private boolean logAndNotifyPluginConfiguration(PluginCfgValidator validator, StringBuilder builder, boolean nextEntry) {
if (!validator.isPluginExists()) {
return false;
}
PluginCfgLogger.logValidationResults(logger,
validator.getConfiguration().getArtifactId(),
validator.getValidationResult());
if (nextEntry) {
builder.append(", ");
}
builder.append(validator.getConfiguration().toString());
String validationResult = validator.getValidationResult().asString();
if (validationResult != null) {
builder.append(", validation result: ").append(validationResult);
}
return true;
}
private void handleArgLineProperty(String slArgument, boolean onSuccess) {
Properties projectProperties = project.getProperties();
initialArgLinePropertyValue = projectProperties.getProperty(ARG_LINE);
setArgLineToEmptyIfNotInitialized(projectProperties);
if (onSuccess || StringUtils.isNotEmpty(initialArgLinePropertyValue)) {
// On failure, only not-null original argLine property should be updated
// On success relevance of argLine update is detected by surefireConfigHandler
String newArgLineProperty = resolveNewArgLineProperty(initialArgLinePropertyValue, slArgument);
if (newArgLineProperty != null) {
logger.info("argLine property set to {}", LogUtil.maskToken(newArgLineProperty));
projectProperties.setProperty(ARG_LINE, newArgLineProperty);
}
}
}
private void setArgLineToEmptyIfNotInitialized(Properties projectProperties) {
PluginConfiguration surefireValidatorConfiguration = surefireValidator.getConfiguration();
PluginConfiguration failsafeValidatorConfiguration = failsafeValidator.getConfiguration();
if (initialArgLinePropertyValue == null && (surefireValidatorConfiguration.hasArgLinePlaceholder() || failsafeValidatorConfiguration.hasArgLinePlaceholder())) {
projectProperties.setProperty(ARG_LINE, "");
}
}
/**
* Builds a new argLine property value, if it is relevant.
* Returns null, if argLine is not relevant
*/
private String resolveNewArgLineProperty(String origArgLine, String slArgument) {
logger.info("Original is: {} and slArgument {}", LogUtil.maskToken(origArgLine), LogUtil.maskToken(slArgument));
if (surefireValidator.isArgLinePropertyRelevant() || failsafeValidator.isArgLinePropertyRelevant()) {
String modifiedArgLine;
if (StringUtils.isNotEmpty(origArgLine)) {
logger.info("The '{}' property is already set to:'{}'", ARG_LINE, origArgLine);
modifiedArgLine = buildArgLine(origArgLine, slArgument);
} else {
logger.info("The modified : '{}'", LogUtil.maskToken(slArgument));
modifiedArgLine = slArgument;
}
return modifiedArgLine;
} else {
if (StringUtils.isNotEmpty(origArgLine)) {
//Not removed just commented
//Because it prints warn when surefire.configuration.argLine contains ${argLine}.
//but looks like in this case ${argLine} will be appended and not ignored
// logger.warn("The defined property '{}={}' will be ignored by {}", ARG_LINE, origArgLine, SUREFIRE_ARTIFACT_ID);
}
logger.info("No modifications will be done");
return null;
}
}
private String buildArgLine(String origArgLine, String slArgument) {
String unduplicatedArgline = ArgLineNormalizer.removeArgLineDuplication(origArgLine);
warnForOtherJavaAgents(unduplicatedArgline);
StringBuilder newArgLine = new StringBuilder(slArgument);
if (!StringUtils.isNullOrEmpty(unduplicatedArgline)) {
newArgLine.append(SPACE);
newArgLine.append(unduplicatedArgline);
}
return newArgLine.toString();
}
private void warnForOtherJavaAgents(String argLineVariable) {
if (argLineVariable != null && argLineVariable.contains(" -javaagent:")) {
PluginCfgLogger.logImportantInfo(logger, "Warning",
"Another java agent is running with SeaLights.",
"This may interfere with the test-listener agent and cause the low code coverage.");
}
}
private String buildFoundString(boolean isFound) {
return isFound ? "found" : "not found";
}
@UtilityClass
static class ArgLineNormalizer {
static int IGNORE_WHITE_SPACES = 0;
static int IN_QUOTES = 1;
static int AFTER_QUOTES = 2;
static int IN_SEQUENCE = 3;
static int ESCAPED = 4;
public static String removeArgLineDuplication(String oldArgLine) {
List args = toArgsArray(oldArgLine);
return deleteSeaLightsLeftovers(args);
}
private static String deleteSeaLightsLeftovers(List args) {
for (Iterator iterator = args.iterator(); iterator.hasNext();) {
String argument = iterator.next();
if (isSeaLightsProperty(argument) || isSeaLightsTestListener(argument)) {
iterator.remove();
}
}
String ret = StringUtils.join(args, ' ');
return ret;
}
private static List toArgsArray(String argsAsString) {
List args = new ArrayList<>();
int state = 0;
StringBuilder currentArg = new StringBuilder();
for (char c : argsAsString.toCharArray()) {
if (state == IGNORE_WHITE_SPACES) {
if (!Character.isWhitespace(c)) {
currentArg.append(c);
if (isQuote(c)) {
state = IN_QUOTES;
}
else {
state = IN_SEQUENCE;
}
}
}
else if (state == IN_QUOTES) {
currentArg.append(c);
if (isQuote(c)) {
state = AFTER_QUOTES;
}
}
else if (state == AFTER_QUOTES) {
if (!Character.isWhitespace(c)) {
currentArg.append(c);
if (isQuote(c)) {
state = IN_QUOTES;
}
else {
state = IN_SEQUENCE;
}
}
else {
args.add(currentArg.toString());
currentArg.setLength(0);
state = IGNORE_WHITE_SPACES;
}
}
else if (state == IN_SEQUENCE){
if (!Character.isWhitespace(c)) {
currentArg.append(c);
if (isQuote(c)) {
state = IN_QUOTES;
}
} else {
args.add(currentArg.toString());
currentArg.setLength(0);
state = IGNORE_WHITE_SPACES;
}
}
}
args.add(currentArg.toString());
return args;
}
private static boolean isQuote(char ch) {
return ch == '"' || ch == '\'';
}
private static boolean isSeaLightsProperty(String argument){
return argument.startsWith("-D" + SLProperties.PREFIX);
}
private static boolean isSeaLightsTestListener(String argument){
return (argument.startsWith("-javaagent:") && ( isValidTestListenerName(argument)));
}
private static boolean isValidTestListenerName(String testListenerName) {
return testListenerName != null && (
testListenerName.contains(SL_TEST_LISTENER) ||
testListenerName.contains(JAVA_TEST_LISTENER) ||
testListenerName.contains(DEV_SL_TEST_LISTENER)
);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy