diff --git a/application-admintools-api/pom.xml b/application-admintools-api/pom.xml index fba7f3f6..187be39b 100644 --- a/application-admintools-api/pom.xml +++ b/application-admintools-api/pom.xml @@ -31,11 +31,20 @@ Admin Tools (Pro) - API Provides the Java APIs needed by the Admin tools Application. + + javax.ws.rs + jsr311-api + org.xwiki.commons xwiki-commons-component-api ${commons.version} + + org.xwiki.platform + xwiki-platform-job-api + ${platform.version} + org.xwiki.platform xwiki-platform-rest-server diff --git a/application-admintools-api/src/main/java/com/xwiki/admintools/health/HealthCheck.java b/application-admintools-api/src/main/java/com/xwiki/admintools/health/HealthCheck.java new file mode 100644 index 00000000..85820595 --- /dev/null +++ b/application-admintools-api/src/main/java/com/xwiki/admintools/health/HealthCheck.java @@ -0,0 +1,42 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.health; + +import org.xwiki.component.annotation.Role; +import org.xwiki.stability.Unstable; + +/** + * Check for issues in the current wiki. + * + * @since 1.0 + * @version $Id$ + */ +@Role +@Unstable +public interface HealthCheck +{ + /** + * Execute the health check on the wiki instance. + * + * @return a {@link HealthCheckResult} with {@code null} values if no issue was found, or with initialized values + * otherwise. + */ + HealthCheckResult check(); +} diff --git a/application-admintools-api/src/main/java/com/xwiki/admintools/health/HealthCheckResult.java b/application-admintools-api/src/main/java/com/xwiki/admintools/health/HealthCheckResult.java new file mode 100644 index 00000000..96d974f4 --- /dev/null +++ b/application-admintools-api/src/main/java/com/xwiki/admintools/health/HealthCheckResult.java @@ -0,0 +1,121 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.health; + +import org.xwiki.stability.Unstable; + +/** + * Result of a health check. May store the error message, severity level, recommendation and the current value of the + * checked resource. The severity level is used as "info", for informative result, "warn" for warnings and "error" + * for critical issues. + * + * @version $Id$ + * @since 1.0 + */ +@Unstable +public class HealthCheckResult +{ + private String message; + + private String recommendation; + + private String level; + + private String currentValue; + + /** + * Used for registering a result. + * + * @param message error message representing the summary of the found issue. + * @param recommendation suggestion in context of the message. + * @param level severity level of a result. + * @param currentValue Current value of the checked resource. + */ + public HealthCheckResult(String message, String recommendation, String level, String currentValue) + { + this.message = message; + this.recommendation = recommendation; + this.level = level; + this.currentValue = currentValue; + } + + /** + * Partial result definition. + * + * @param message error message representing the summary of the found issue. + * @param recommendation suggestion in context of the message. + * @param level severity level of a result. + */ + public HealthCheckResult(String message, String recommendation, String level) + { + this(message, recommendation, level, null); + } + + /** + * Simple result definition. + * + * @param message error message representing the summary of the found issue. + * @param level severity level of a result. + */ + public HealthCheckResult(String message, String level) + { + this(message, null, level); + } + + /** + * Get the error body. + * + * @return a summary of the error. + */ + public String getMessage() + { + return message; + } + + /** + * Get the recommendation for the set error. + * + * @return a suggestion for fixing the error. + */ + public String getRecommendation() + { + return recommendation; + } + + /** + * Get the severity level a detected error. + * + * @return the severity level of an error. + */ + public String getLevel() + { + return level; + } + + /** + * Get the value of a checked resource. + * + * @return the value of a checked resource. + */ + public String getCurrentValue() + { + return currentValue; + } +} diff --git a/application-admintools-api/src/main/java/com/xwiki/admintools/jobs/HealthCheckJobRequest.java b/application-admintools-api/src/main/java/com/xwiki/admintools/jobs/HealthCheckJobRequest.java new file mode 100644 index 00000000..0ad1d0a6 --- /dev/null +++ b/application-admintools-api/src/main/java/com/xwiki/admintools/jobs/HealthCheckJobRequest.java @@ -0,0 +1,59 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.jobs; + +import java.util.List; + +import org.xwiki.job.AbstractRequest; +import org.xwiki.stability.Unstable; + +/** + * Represents a request to start a health check on current wiki. + * + * @version $Id$ + * @since 1.0 + */ +@Unstable +public class HealthCheckJobRequest extends AbstractRequest +{ + /** + * Default constructor. + */ + public HealthCheckJobRequest() + { + setDefaultId(); + } + + /** + * Creates a request specific to the wiki from which the call was made. + * + * @param requestId the ID for the request. + */ + public HealthCheckJobRequest(List requestId) + { + setId(requestId); + } + + private void setDefaultId() + { + List id = List.of("adminTools", "healthCheck"); + setId(id); + } +} diff --git a/application-admintools-api/src/main/java/com/xwiki/admintools/jobs/HealthCheckJobStatus.java b/application-admintools-api/src/main/java/com/xwiki/admintools/jobs/HealthCheckJobStatus.java new file mode 100644 index 00000000..1d70b2ba --- /dev/null +++ b/application-admintools-api/src/main/java/com/xwiki/admintools/jobs/HealthCheckJobStatus.java @@ -0,0 +1,83 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.jobs; + +import java.util.LinkedList; +import java.util.List; + +import org.xwiki.job.DefaultJobStatus; +import org.xwiki.logging.LoggerManager; +import org.xwiki.observation.ObservationManager; +import org.xwiki.stability.Unstable; + +import com.xwiki.admintools.health.HealthCheckResult; + +/** + * The status of the health check job. + * + * @version $Id$ + * @since 1.0 + */ +@Unstable +public class HealthCheckJobStatus extends DefaultJobStatus +{ + private final List healthCheckResults = new LinkedList<>(); + + /** + * Create a new health check job status. + * + * @param jobType the job type + * @param request the request provided when the job was started + * @param observationManager the observation manager + * @param loggerManager the logger manager + */ + public HealthCheckJobStatus(String jobType, HealthCheckJobRequest request, ObservationManager observationManager, + LoggerManager loggerManager) + { + super(jobType, request, null, observationManager, loggerManager); + setCancelable(true); + } + + /** + * Get the list issues list from the job. + * + * @return list with {@link HealthCheckResult} containing errors. + */ + public List getHealthCheckResults() + { + return healthCheckResults; + } + + /** + * Get the list issues list from the job. + * @param level the logger manager + * + * @return boolean with {@link HealthCheckResult} containing errors. + */ + public boolean hasErrorLevel(String level) + { + for (HealthCheckResult checkResult : healthCheckResults) { + if (checkResult.getLevel().equals(level)) { + return true; + } + } + return false; + } +} diff --git a/application-admintools-default/pom.xml b/application-admintools-default/pom.xml index c7138581..5f6b55f8 100644 --- a/application-admintools-default/pom.xml +++ b/application-admintools-default/pom.xml @@ -41,6 +41,12 @@ xwiki-platform-oldcore ${platform.version} + + + com.github.oshi + oshi-core + 5.8.0 + javax.servlet javax.servlet-api @@ -66,8 +72,13 @@ ${commons.version} test + + org.xwiki.commons + xwiki-commons-cache-api + ${commons.version} + - 0.79 + 0.76 \ No newline at end of file diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/AdminToolsManager.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/AdminToolsManager.java index 8a388397..af546c4d 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/AdminToolsManager.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/AdminToolsManager.java @@ -19,14 +19,16 @@ */ package com.xwiki.admintools.internal; -import java.util.ArrayList; import java.util.List; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; import org.xwiki.component.annotation.Component; +import org.xwiki.component.manager.ComponentLookupException; +import org.xwiki.component.manager.ComponentManager; import com.xwiki.admintools.DataProvider; import com.xwiki.admintools.internal.data.identifiers.CurrentServer; @@ -56,6 +58,10 @@ public class AdminToolsManager @Inject private ImportantFilesManager importantFilesManager; + @Inject + @Named("context") + private ComponentManager contextComponentManager; + /** * Get data generated in a specific format, using a template, by each provider and merge it. * @@ -78,14 +84,14 @@ public String generateData() * @param hint {@link String} represents the data provider identifier. * @return a {@link String} representing a template */ - public String generateData(String hint) + public String generateData(String hint) throws ComponentLookupException { - for (DataProvider dataProvider : this.dataProviderProvider.get()) { - if (dataProvider.getIdentifier().equals(hint)) { - return dataProvider.getRenderedData(); - } + try { + DataProvider dataProvider = contextComponentManager.getInstance(DataProvider.class, hint); + return dataProvider.getRenderedData(); + } catch (ComponentLookupException e) { + throw e; } - return null; } /** @@ -95,7 +101,7 @@ public String generateData(String hint) */ public List getSupportedDBs() { - return new ArrayList<>(this.currentServer.getSupportedDBs().values()); + return this.currentServer.getSupportedDBs(); } /** diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/CurrentServer.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/CurrentServer.java index 35b7551d..1984b21e 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/CurrentServer.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/CurrentServer.java @@ -20,9 +20,7 @@ package com.xwiki.admintools.internal.data.identifiers; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import javax.inject.Inject; import javax.inject.Provider; @@ -65,19 +63,13 @@ public ServerIdentifier getCurrentServer() } /** - * Get a {@link Map} with the supported databases. + * Get a {@link List} with the supported databases. * * @return the supported databases. */ - public Map getSupportedDBs() + public List getSupportedDBs() { - Map supportedDBs = new HashMap<>(); - supportedDBs.put("mysql", "MySQL"); - supportedDBs.put("hsqldb", "HSQLDB"); - supportedDBs.put("mariadb", "MariaDB"); - supportedDBs.put("postgresql", "PostgreSQL"); - supportedDBs.put("oracle", "Oracle"); - return supportedDBs; + return List.of("MySQL", "HSQL", "MariaDB", "PostgreSQL", "Oracle"); } /** diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/ImportantFilesManager.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/ImportantFilesManager.java index 426afe94..7e15e5c2 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/ImportantFilesManager.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/ImportantFilesManager.java @@ -21,19 +21,20 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.zip.ZipOutputStream; import javax.inject.Inject; -import javax.inject.Provider; +import javax.inject.Named; import javax.inject.Singleton; import javax.script.ScriptContext; import org.apache.commons.lang3.exception.ExceptionUtils; import org.slf4j.Logger; import org.xwiki.component.annotation.Component; +import org.xwiki.component.manager.ComponentLookupException; +import org.xwiki.component.manager.ComponentManager; import org.xwiki.script.ScriptContextManager; import org.xwiki.template.TemplateManager; @@ -54,7 +55,8 @@ public class ImportantFilesManager private static final String REQUESTED_FILES_KEY = "files"; @Inject - private Provider> dataResources; + @Named("context") + private ComponentManager contextComponentManager; @Inject private TemplateManager templateManager; @@ -141,13 +143,8 @@ public String renderTemplate() } } - private DataResource findDataResource(String hint) + private DataResource findDataResource(String hint) throws ComponentLookupException { - for (DataResource archiverDataResource : dataResources.get()) { - if (archiverDataResource.getIdentifier().equals(hint)) { - return archiverDataResource; - } - } - return null; + return contextComponentManager.getInstance(DataResource.class, hint); } } diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/configuration/AbstractConfigurationHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/configuration/AbstractConfigurationHealthCheck.java new file mode 100644 index 00000000..dbc378d1 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/configuration/AbstractConfigurationHealthCheck.java @@ -0,0 +1,63 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.configuration; + +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.slf4j.Logger; + +import com.xwiki.admintools.DataProvider; +import com.xwiki.admintools.health.HealthCheck; +import com.xwiki.admintools.internal.data.ConfigurationDataProvider; + +/** + * {@link HealthCheck} implementations to simplify the code for configuration related health checks. + * + * @version $Id$ + */ +public abstract class AbstractConfigurationHealthCheck implements HealthCheck +{ + @Inject + protected Logger logger; + + @Inject + @Named(ConfigurationDataProvider.HINT) + private DataProvider configurationDataProvider; + + /** + * Retrieve a JSON containing the necessary instance configuration information required for executing the + * configuration health checks. + * + * @return a {@link Map} with the {@link ConfigurationDataProvider} info, or an empty {@link Map} in case of an + * error. + */ + protected Map getConfigurationProviderJSON() + { + try { + return configurationDataProvider.getDataAsJSON(); + } catch (Exception e) { + return new HashMap<>(); + } + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationDatabaseHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationDatabaseHealthCheck.java new file mode 100644 index 00000000..3f4d3f00 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationDatabaseHealthCheck.java @@ -0,0 +1,68 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.configuration; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.xwiki.component.annotation.Component; + +import com.xwiki.admintools.health.HealthCheckResult; +import com.xwiki.admintools.internal.data.identifiers.CurrentServer; + +/** + * Extension of {@link AbstractConfigurationHealthCheck} for checking the database configuration. + * + * @version $Id$ + */ +@Component +@Named(ConfigurationDatabaseHealthCheck.HINT) +@Singleton +public class ConfigurationDatabaseHealthCheck extends AbstractConfigurationHealthCheck +{ + /** + * Component identifier. + */ + public static final String HINT = "configurationDatabase"; + + private static final String ERROR_KEY = "error"; + + @Inject + private CurrentServer currentServer; + + @Override + public HealthCheckResult check() + { + String usedDatabase = getConfigurationProviderJSON().get("databaseName"); + if (usedDatabase == null) { + logger.warn("Database not found!"); + return new HealthCheckResult("adminTools.dashboard.healthcheck.database.warn", ERROR_KEY); + } + if (currentServer.getSupportedDBs().stream() + .anyMatch(d -> usedDatabase.toLowerCase().contains(d.toLowerCase()))) + { + return new HealthCheckResult("adminTools.dashboard.healthcheck.database.info", "info"); + } + logger.error("Used database is not supported!"); + return new HealthCheckResult("adminTools.dashboard.healthcheck.database.notSupported", + "adminTools.dashboard.healthcheck.database.recommendation", ERROR_KEY, usedDatabase); + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationJavaHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationJavaHealthCheck.java new file mode 100644 index 00000000..e3596c50 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationJavaHealthCheck.java @@ -0,0 +1,99 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.configuration; + +import java.util.Map; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.xwiki.component.annotation.Component; + +import com.xwiki.admintools.health.HealthCheckResult; + +/** + * Extension of {@link AbstractConfigurationHealthCheck} for checking the Java configuration. + * + * @version $Id$ + */ +@Component +@Named(ConfigurationJavaHealthCheck.HINT) +@Singleton +public class ConfigurationJavaHealthCheck extends AbstractConfigurationHealthCheck +{ + /** + * Component identifier. + */ + public static final String HINT = "configurationJava"; + + @Override + public HealthCheckResult check() + { + Map configurationJson = getConfigurationProviderJSON(); + String javaVersionString = configurationJson.get("javaVersion"); + if (javaVersionString == null) { + logger.warn("Java version not found!"); + return new HealthCheckResult("adminTools.dashboard.healthcheck.java.warn", + "adminTools.dashboard.healthcheck.java.warn.recommendation", "warn"); + } + String xwikiVersionString = configurationJson.get("xwikiVersion"); + float xwikiVersion = parseFloat(xwikiVersionString); + float javaVersion = parseFloat(javaVersionString); + if (isNotJavaXWikiCompatible(xwikiVersion, javaVersion)) { + logger.error("Java version is not compatible with the current XWiki installation!"); + return new HealthCheckResult("adminTools.dashboard.healthcheck.java.error", + "adminTools.dashboard.healthcheck.java.error.recommendation", "error", + String.format("Java %s - XWiki %s", javaVersion, xwikiVersion)); + } + return new HealthCheckResult("adminTools.dashboard.healthcheck.java.info", "info"); + } + + private static float parseFloat(String javaVersionString) + { + String[] parts = javaVersionString.split("\\."); + return Float.parseFloat(parts[0] + "." + parts[1]); + } + + private boolean isNotJavaXWikiCompatible(float xwikiVersion, float javaVersion) + { + boolean isCompatible = false; + + if (inInterval(xwikiVersion, 0, 6)) { + isCompatible = javaVersion != 1.6; + } else if (inInterval(xwikiVersion, 6, 8.1f)) { + isCompatible = javaVersion != 1.7; + } else if (inInterval(xwikiVersion, 8.1f, 11.3f)) { + isCompatible = javaVersion != 1.8; + } else if (inInterval(xwikiVersion, 11.2f, 14)) { + isCompatible = (javaVersion != 1.8) || inInterval(javaVersion, 10.99f, 12); + } else if (inInterval(xwikiVersion, 13.9f, 14.10f)) { + isCompatible = javaVersion >= 11; + } else if (inInterval(xwikiVersion, 14.10f, Float.MAX_VALUE)) { + isCompatible = inInterval(javaVersion, 10.99f, 12) || inInterval(javaVersion, 16.99f, 18); + } + + return isCompatible; + } + + private boolean inInterval(float checkedValue, float lowerBound, float upperBound) + { + return checkedValue > lowerBound && checkedValue < upperBound; + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationOSHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationOSHealthCheck.java new file mode 100644 index 00000000..14858eb5 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationOSHealthCheck.java @@ -0,0 +1,56 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.configuration; + +import java.util.Map; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.xwiki.component.annotation.Component; + +import com.xwiki.admintools.health.HealthCheckResult; + +/** + * Extension of {@link AbstractConfigurationHealthCheck} for checking the OS configuration. + * + * @version $Id$ + */ +@Component +@Named(ConfigurationOSHealthCheck.HINT) +@Singleton +public class ConfigurationOSHealthCheck extends AbstractConfigurationHealthCheck +{ + /** + * Component identifier. + */ + public static final String HINT = "configurationOS"; + + @Override + public HealthCheckResult check() + { + Map dataJSON = getConfigurationProviderJSON(); + if (dataJSON.get("osName") == null || dataJSON.get("osVersion") == null || dataJSON.get("osArch") == null) { + logger.warn("There has been an error while gathering OS info!"); + return new HealthCheckResult("adminTools.dashboard.healthcheck.os.warn", "warn"); + } + return new HealthCheckResult("adminTools.dashboard.healthcheck.os.info", "info"); + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/memory/CacheMemoryHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/memory/CacheMemoryHealthCheck.java new file mode 100644 index 00000000..0acbcf49 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/memory/CacheMemoryHealthCheck.java @@ -0,0 +1,74 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.memory; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.slf4j.Logger; +import org.xwiki.component.annotation.Component; +import org.xwiki.configuration.ConfigurationSource; + +import com.xwiki.admintools.health.HealthCheck; +import com.xwiki.admintools.health.HealthCheckResult; + +/** + * Implementation of {@link HealthCheck} for checking instance document cache performance. + * + * @version $Id$ + */ +@Component +@Named(CacheMemoryHealthCheck.HINT) +@Singleton +public class CacheMemoryHealthCheck implements HealthCheck +{ + /** + * Component identifier. + */ + public static final String HINT = "CACHE_MEMORY_HEALTH_CHECK"; + + private static final String INFO_LEVEL = "info"; + + @Inject + @Named("xwikicfg") + private ConfigurationSource configurationSource; + + @Inject + private Logger logger; + + @Override + public HealthCheckResult check() + { + String storeCacheCapacity = configurationSource.getProperty("xwiki.store.cache.capacity"); + if (storeCacheCapacity == null) { + logger.warn("Store cache capacity not defined. Set by default at 500."); + return new HealthCheckResult("adminTools.dashboard.healthcheck.memory.cache.null", + "adminTools.dashboard.healthcheck.memory.cache.null.recommendation", INFO_LEVEL); + } + if (Integer.parseInt(storeCacheCapacity) <= 500) { + logger.warn("Store cache capacity is set to [{}].", storeCacheCapacity); + return new HealthCheckResult("adminTools.dashboard.healthcheck.memory.cache.low", null, "warn", + storeCacheCapacity); + } + return new HealthCheckResult("adminTools.dashboard.healthcheck.memory.cache.info", null, INFO_LEVEL, + storeCacheCapacity); + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/memory/MemoryHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/memory/MemoryHealthCheck.java new file mode 100644 index 00000000..db3664b6 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/memory/MemoryHealthCheck.java @@ -0,0 +1,89 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.memory; + +import java.text.DecimalFormat; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; + +import org.slf4j.Logger; +import org.xwiki.component.annotation.Component; + +import com.xpn.xwiki.XWiki; +import com.xpn.xwiki.XWikiContext; +import com.xwiki.admintools.health.HealthCheck; +import com.xwiki.admintools.health.HealthCheckResult; + +/** + * Implementation of {@link HealthCheck} for checking instance memory performance. + * + * @version $Id$ + */ +@Component +@Named(MemoryHealthCheck.HINT) +@Singleton +public class MemoryHealthCheck implements HealthCheck +{ + /** + * Component identifier. + */ + public static final String HINT = "MEMORY_HEALTH_CHECK"; + + private static final String MEMORY_RECOMMENDATION = "adminTools.dashboard.healthcheck.memory.recommendation"; + + private static final String MB_UNIT = "MB"; + + private static final String ERROR_LEVEL = "error"; + + @Inject + protected Provider xcontextProvider; + + @Inject + private Logger logger; + + @Override + public HealthCheckResult check() + { + XWiki wiki = xcontextProvider.get().getWiki(); + float maxMemory = wiki.maxMemory(); + float totalFreeMemory = (maxMemory - (wiki.totalMemory() - wiki.freeMemory())) / (1024.0f * 1024); + float maxMemoryGB = maxMemory / (1024.0f * 1024 * 1024); + DecimalFormat format = new DecimalFormat("0.#"); + if (maxMemoryGB < 1) { + logger.error("JVM memory is less than 1024MB. Currently: [{}]", maxMemoryGB * 1024); + return new HealthCheckResult("adminTools.dashboard.healthcheck.memory.maxcapacity.error", + MEMORY_RECOMMENDATION, ERROR_LEVEL, format.format(maxMemoryGB * 1024) + MB_UNIT); + } + if (totalFreeMemory < 512) { + logger.error("JVM instance has only [{}]MB free memory left!", totalFreeMemory); + return new HealthCheckResult("adminTools.dashboard.healthcheck.memory.free.error", MEMORY_RECOMMENDATION, + ERROR_LEVEL, format.format(totalFreeMemory) + MB_UNIT); + } else if (totalFreeMemory < 1024) { + logger.warn("Instance memory is running low. Currently only [{}]MB free left.", totalFreeMemory); + return new HealthCheckResult("adminTools.dashboard.healthcheck.memory.free.warn", MEMORY_RECOMMENDATION, + "warn", format.format(totalFreeMemory) + MB_UNIT); + } + return new HealthCheckResult("adminTools.dashboard.healthcheck.memory.info", null, "info", + String.format(" %s GB", format.format(totalFreeMemory / 1024))); + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/CPUHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/CPUHealthCheck.java new file mode 100644 index 00000000..2a86b707 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/CPUHealthCheck.java @@ -0,0 +1,71 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.performance; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.slf4j.Logger; +import org.xwiki.component.annotation.Component; + +import com.xwiki.admintools.health.HealthCheck; +import com.xwiki.admintools.health.HealthCheckResult; + +import oshi.SystemInfo; +import oshi.hardware.CentralProcessor; +import oshi.hardware.HardwareAbstractionLayer; + +/** + * Implementation of {@link HealthCheck} for checking if system CPU meets XWiki requirements. + * + * @version $Id$ + */ +@Component +@Named(CPUHealthCheck.HINT) +@Singleton +public class CPUHealthCheck implements HealthCheck +{ + /** + * Component identifier. + */ + public static final String HINT = "cpuPerformance"; + + @Inject + private Logger logger; + + @Override + public HealthCheckResult check() + { + SystemInfo systemInfo = new SystemInfo(); + HardwareAbstractionLayer hardware = systemInfo.getHardware(); + CentralProcessor processor = hardware.getProcessor(); + int cpuCores = processor.getPhysicalProcessorCount(); + long maxFreq = processor.getMaxFreq() / (1024 * 1024); + + if (cpuCores > 2 && maxFreq > 2048) { + return new HealthCheckResult("adminTools.dashboard.healthcheck.performance.cpu.info", "info"); + } + String cpuSpecifications = String.format("CPU cores %d - frequency %d", cpuCores, maxFreq); + logger.warn("The CPU does not satisfy the minimum system requirements! [{}]", cpuSpecifications); + return new HealthCheckResult("adminTools.dashboard.healthcheck.performance.cpu.warn", + "adminTools.dashboard.healthcheck.performance.cpu.recommendation", "error", cpuSpecifications); + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/LogsSizeCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/LogsSizeCheck.java new file mode 100644 index 00000000..243b0870 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/LogsSizeCheck.java @@ -0,0 +1,87 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.performance; + +import java.io.File; +import java.text.DecimalFormat; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.xwiki.component.annotation.Component; + +import com.xwiki.admintools.ServerIdentifier; +import com.xwiki.admintools.health.HealthCheck; +import com.xwiki.admintools.health.HealthCheckResult; +import com.xwiki.admintools.internal.data.identifiers.CurrentServer; + +@Component +@Named(LogsSizeCheck.HINT) +@Singleton +public class LogsSizeCheck implements HealthCheck +{ + /** + * Component identifier. + */ + public static final String HINT = "logSize"; + + @Inject + private CurrentServer currentServer; + + @Override + public HealthCheckResult check() + { + ServerIdentifier server = currentServer.getCurrentServer(); + + long logsSize = getFolderSize(server.getLogsFolderPath()); + + String[] units = new String[] { "B", "KB", "MB", "GB" }; + int unitIndex = (int) (Math.log10(logsSize) / 3); + double unitValue = 1 << (unitIndex * 10); + + String readableSize = new DecimalFormat("#,##0.#").format(logsSize / unitValue) + " " + units[unitIndex]; + + // NEED TO SET SOME METRICS. WHAT LOG SIZE IS TOO BIG? + if (logsSize / (1024 * 1024) > 500) { + return new HealthCheckResult("adminTools.dashboard.healthcheck.performance.cpu.info", "info"); + } else { + return new HealthCheckResult("adminTools.dashboard.healthcheck.performance.cpu.warn", + "adminTools.dashboard.healthcheck.performance.cpu.recommendation", "error", "cpuSpecifications"); + } + } + + public static long getFolderSize(String folderPath) + { + File folder = new File(folderPath); + long length = 0; + File[] files = folder.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isFile()) { + length += file.length(); + } else { + length += getFolderSize(file.getAbsolutePath()); + } + } + } + return length; + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/PhysicalMemoryHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/PhysicalMemoryHealthCheck.java new file mode 100644 index 00000000..3eeb9462 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/PhysicalMemoryHealthCheck.java @@ -0,0 +1,72 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.performance; + +import java.text.DecimalFormat; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.slf4j.Logger; +import org.xwiki.component.annotation.Component; + +import com.xwiki.admintools.health.HealthCheck; +import com.xwiki.admintools.health.HealthCheckResult; + +import oshi.SystemInfo; +import oshi.hardware.HardwareAbstractionLayer; + +/** + * Implementation of {@link HealthCheck} for checking if system memory meets XWiki requirements. + * + * @version $Id$ + */ +@Component +@Named(PhysicalMemoryHealthCheck.HINT) +@Singleton +public class PhysicalMemoryHealthCheck implements HealthCheck +{ + /** + * Component identifier. + */ + public static final String HINT = "physicalMemory"; + + @Inject + private Logger logger; + + @Override + public HealthCheckResult check() + { + SystemInfo systemInfo = new SystemInfo(); + HardwareAbstractionLayer hardware = systemInfo.getHardware(); + + float totalMemory = (float) hardware.getMemory().getTotal() / (1024 * 1024 * 1024); + DecimalFormat format = new DecimalFormat("0.#"); + String systemCapacityMessage = String.format("%s GB", format.format(totalMemory)); + if (totalMemory > 2) { + return new HealthCheckResult("adminTools.dashboard.healthcheck.performance.memory.info", "info"); + } + logger.warn("There is not enough memory to safely run the XWiki installation! Physical memory detected: [{}]", + systemCapacityMessage); + return new HealthCheckResult("adminTools.dashboard.healthcheck.performance.memory.warn", + "adminTools.dashboard.healthcheck.performance.memory.recommendation", "error", systemCapacityMessage); + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/PhysicalSpaceHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/PhysicalSpaceHealthCheck.java new file mode 100644 index 00000000..70f77550 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/PhysicalSpaceHealthCheck.java @@ -0,0 +1,88 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.performance; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.slf4j.Logger; +import org.xwiki.component.annotation.Component; + +import com.xwiki.admintools.ServerIdentifier; +import com.xwiki.admintools.health.HealthCheck; +import com.xwiki.admintools.health.HealthCheckResult; +import com.xwiki.admintools.internal.data.identifiers.CurrentServer; + +/** + * Implementation of {@link HealthCheck} for checking if system free space XWiki requirements. + * + * @version $Id$ + */ +@Component +@Named(PhysicalSpaceHealthCheck.HINT) +@Singleton +public class PhysicalSpaceHealthCheck implements HealthCheck +{ + /** + * Component identifier. + */ + public static final String HINT = "physicalSpace"; + + @Inject + private CurrentServer currentServer; + + @Inject + private Logger logger; + + @Override + public HealthCheckResult check() + { + File diskPartition; + ServerIdentifier server = currentServer.getCurrentServer(); + if (server == null) { + if (System.getProperty("os.name").toLowerCase().contains("windows")) { + diskPartition = new File("C:"); + } else { + diskPartition = new File("/"); + } + } else { + Path xwikiPath = Paths.get(server.getXwikiCfgFolderPath()); + Path rootDrive = xwikiPath.getRoot(); + diskPartition = new File(String.valueOf(rootDrive)); + } + long freePartitionSpace = diskPartition.getFreeSpace(); + float freeSpace = (float) freePartitionSpace / (1024 * 1024 * 1024); + + String systemFreeSpaceSizeMessage = String.format("%s: %f GB", diskPartition.getAbsolutePath(), freeSpace); + + if (freeSpace > 16) { + return new HealthCheckResult("adminTools.dashboard.healthcheck.performance.space.info", "info"); + } + logger.warn("There is not enough free space for the XWiki installation! Current free space is [{}]", + systemFreeSpaceSizeMessage); + return new HealthCheckResult("adminTools.dashboard.healthcheck.performance.space.warn", + "adminTools.dashboard.healthcheck.performance.space.recommendation", "error", systemFreeSpaceSizeMessage); + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/AbstractSecurityHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/AbstractSecurityHealthCheck.java new file mode 100644 index 00000000..d724a2ec --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/AbstractSecurityHealthCheck.java @@ -0,0 +1,69 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.security; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.slf4j.Logger; + +import com.xwiki.admintools.DataProvider; +import com.xwiki.admintools.health.HealthCheck; +import com.xwiki.admintools.internal.data.SecurityDataProvider; + +/** + * {@link HealthCheck} implementations to simplify the code for security related health checks. + * + * @version $Id$ + */ +public abstract class AbstractSecurityHealthCheck implements HealthCheck +{ + protected final List acceptedEncodings = new ArrayList<>(List.of("UTF8", "UTF-8", "utf8", "utf-8")); + + @Inject + protected Logger logger; + + @Inject + @Named(SecurityDataProvider.HINT) + private DataProvider securityDataProvider; + + protected boolean isSafeEncoding(String encoding, String type) + { + if (acceptedEncodings.contains(encoding)) { + return true; + } + logger.warn("[{}] encoding is [{}], but should be UTF-8!", type, encoding); + return false; + } + + protected Map getSecurityProviderJSON() + { + try { + return securityDataProvider.getDataAsJSON(); + } catch (Exception e) { + return new HashMap<>(); + } + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/ActiveEncodingHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/ActiveEncodingHealthCheck.java new file mode 100644 index 00000000..65ffdf05 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/ActiveEncodingHealthCheck.java @@ -0,0 +1,61 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.security; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.xwiki.component.annotation.Component; + +import com.xwiki.admintools.health.HealthCheckResult; + +/** + * Extension of {@link AbstractSecurityHealthCheck} for checking XWiki active encoding. + * + * @version $Id$ + */ +@Component +@Named(ActiveEncodingHealthCheck.HINT) +@Singleton +public class ActiveEncodingHealthCheck extends AbstractSecurityHealthCheck +{ + /** + * Component identifier. + */ + public static final String HINT = "activeEncoding"; + + private static final String WARN_LEVEL = "warn"; + + @Override + public HealthCheckResult check() + { + String activeEnc = getSecurityProviderJSON().get(HINT); + if (activeEnc == null) { + logger.warn("Active encoding could not be detected!"); + return new HealthCheckResult("adminTools.dashboard.healthcheck.security.xwiki.active.notFound", WARN_LEVEL); + } + boolean isActiveEncSafe = isSafeEncoding(activeEnc, "XWiki active"); + if (!isActiveEncSafe) { + return new HealthCheckResult("adminTools.dashboard.healthcheck.security.xwiki.active.warn", null, + WARN_LEVEL, activeEnc); + } + return new HealthCheckResult("adminTools.dashboard.healthcheck.security.xwiki.active.info", "info"); + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/ConfigurationEncodingHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/ConfigurationEncodingHealthCheck.java new file mode 100644 index 00000000..1060fdc5 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/ConfigurationEncodingHealthCheck.java @@ -0,0 +1,62 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.security; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.xwiki.component.annotation.Component; + +import com.xwiki.admintools.health.HealthCheckResult; + +/** + * Extension of {@link AbstractSecurityHealthCheck} for checking XWiki configuration encoding. + * + * @version $Id$ + */ +@Component +@Named(ConfigurationEncodingHealthCheck.HINT) +@Singleton +public class ConfigurationEncodingHealthCheck extends AbstractSecurityHealthCheck +{ + /** + * Component identifier. + */ + public static final String HINT = "configurationEncoding"; + + private static final String WARN_LEVEL = "warn"; + + @Override + public HealthCheckResult check() + { + String configEnc = getSecurityProviderJSON().get(HINT); + if (configEnc == null) { + logger.warn("Configuration encoding could not be detected!"); + return new HealthCheckResult("adminTools.dashboard.healthcheck.security.xwiki.config.notFound", WARN_LEVEL); + } + boolean isConfigEncSafe = isSafeEncoding(configEnc, "XWiki configuration"); + + if (!isConfigEncSafe) { + return new HealthCheckResult("adminTools.dashboard.healthcheck.security.xwiki.config.warn", null, + WARN_LEVEL, configEnc); + } + return new HealthCheckResult("adminTools.dashboard.healthcheck.security.xwiki.config.info", "info"); + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/FileEncodingHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/FileEncodingHealthCheck.java new file mode 100644 index 00000000..fb81aefa --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/FileEncodingHealthCheck.java @@ -0,0 +1,61 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.security; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.xwiki.component.annotation.Component; + +import com.xwiki.admintools.health.HealthCheckResult; + +/** + * Extension of {@link AbstractSecurityHealthCheck} for checking system file encoding. + * + * @version $Id$ + */ +@Component +@Named(FileEncodingHealthCheck.HINT) +@Singleton +public class FileEncodingHealthCheck extends AbstractSecurityHealthCheck +{ + /** + * Component identifier. + */ + public static final String HINT = "fileEncoding"; + + private static final String WARN_LEVEL = "warn"; + + @Override + public HealthCheckResult check() + { + String fileEnc = getSecurityProviderJSON().get(HINT); + if (fileEnc == null) { + logger.warn("File encoding could not be detected!"); + return new HealthCheckResult("adminTools.dashboard.healthcheck.security.system.file.notFound", WARN_LEVEL); + } + boolean isSafeFileEnc = isSafeEncoding(fileEnc, "System file"); + if (!isSafeFileEnc) { + return new HealthCheckResult("adminTools.dashboard.healthcheck.security.system.file.warn", + "adminTools.dashboard.healthcheck.security.system.recommendation", WARN_LEVEL, fileEnc); + } + return new HealthCheckResult("adminTools.dashboard.healthcheck.security.system.file.info", "info"); + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/LangEncodingHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/LangEncodingHealthCheck.java new file mode 100644 index 00000000..6568b23b --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/security/LangEncodingHealthCheck.java @@ -0,0 +1,61 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.security; + +import javax.inject.Named; +import javax.inject.Singleton; + +import org.xwiki.component.annotation.Component; + +import com.xwiki.admintools.health.HealthCheckResult; + +/** + * Extension of {@link AbstractSecurityHealthCheck} for checking system language configuration. + * + * @version $Id$ + */ +@Component +@Named(LangEncodingHealthCheck.HINT) +@Singleton +public class LangEncodingHealthCheck extends AbstractSecurityHealthCheck +{ + /** + * Component identifier. + */ + public static final String HINT = "languageEncoding"; + + private static final String WARN_LEVEL = "warn"; + + @Override + public HealthCheckResult check() + { + String langEnc = getSecurityProviderJSON().get("LANG"); + if (langEnc == null) { + logger.warn("Language encoding could not be detected!"); + return new HealthCheckResult("adminTools.dashboard.healthcheck.security.system.lang.notFound", WARN_LEVEL); + } + boolean isSafeLangEnc = isSafeEncoding(langEnc.split("\\.")[1], "System language"); + if (!isSafeLangEnc) { + return new HealthCheckResult("adminTools.dashboard.healthcheck.security.system.lang.warn", + "adminTools.dashboard.healthcheck.security.system.recommendation", WARN_LEVEL, langEnc); + } + return new HealthCheckResult("adminTools.dashboard.healthcheck.security.system.lang.info", "info"); + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/job/HealthCheckJob.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/job/HealthCheckJob.java new file mode 100644 index 00000000..21803fa7 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/job/HealthCheckJob.java @@ -0,0 +1,108 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.job; + +import java.util.Iterator; +import java.util.List; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; + +import org.xwiki.component.annotation.Component; +import org.xwiki.job.AbstractJob; +import org.xwiki.job.GroupedJob; +import org.xwiki.job.JobGroupPath; + +import com.xpn.xwiki.XWikiContext; +import com.xwiki.admintools.health.HealthCheck; +import com.xwiki.admintools.health.HealthCheckResult; +import com.xwiki.admintools.jobs.HealthCheckJobRequest; +import com.xwiki.admintools.jobs.HealthCheckJobStatus; + +/** + * The Admin Tools health check job. + * + * @version $Id$ + */ +@Component +@Named(HealthCheckJob.JOB_TYPE) +public class HealthCheckJob extends AbstractJob implements GroupedJob +{ + /** + * Admin Tools health check job type. + */ + public static final String JOB_TYPE = "admintools.healthcheck"; + + @Inject + private Provider> healthChecks; + + @Inject + private Provider wikiContextProvider; + + @Override + public String getType() + { + return JOB_TYPE; + } + + @Override + public JobGroupPath getGroupPath() + { + XWikiContext wikiContext = wikiContextProvider.get(); + String wikiId = wikiContext.getWikiId(); + return new JobGroupPath(List.of("adminTools", "healthCheck", wikiId)); + } + + @Override + protected HealthCheckJobStatus createNewStatus(HealthCheckJobRequest request) + { + return new HealthCheckJobStatus(JOB_TYPE, request, observationManager, loggerManager); + } + + /** + * Run the health check job. + */ + @Override + protected void runInternal() + { + List healthCheckList = healthChecks.get(); + this.progressManager.pushLevelProgress(healthCheckList.size(), this); + Iterator healthCheckIterator = healthCheckList.iterator(); + try { + while (healthCheckIterator.hasNext()) { + if (status.isCanceled()) { + break; + } else { + progressManager.startStep(this); + // We start the check for the current HealthCheck in the iterator. + HealthCheckResult checkResult = healthCheckIterator.next().check(); + // If the check return a result with a null error message then no issue was found, so we do not + // add the result to the status HealthCheckResult list. + status.getHealthCheckResults().add(checkResult); + progressManager.endStep(this); + Thread.yield(); + } + } + } finally { + this.progressManager.popLevelProgress(this); + } + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/script/AdminToolsScriptService.java b/application-admintools-default/src/main/java/com/xwiki/admintools/script/AdminToolsScriptService.java index b5941937..7cb773fb 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/script/AdminToolsScriptService.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/script/AdminToolsScriptService.java @@ -23,13 +23,22 @@ import javax.inject.Inject; import javax.inject.Named; +import javax.inject.Provider; import javax.inject.Singleton; +import org.apache.commons.lang.exception.ExceptionUtils; +import org.slf4j.Logger; import org.xwiki.component.annotation.Component; +import org.xwiki.component.manager.ComponentLookupException; +import org.xwiki.job.Job; +import org.xwiki.job.JobExecutor; import org.xwiki.script.service.ScriptService; import org.xwiki.stability.Unstable; +import com.xpn.xwiki.XWikiContext; import com.xwiki.admintools.internal.AdminToolsManager; +import com.xwiki.admintools.internal.health.job.HealthCheckJob; +import com.xwiki.admintools.jobs.HealthCheckJobRequest; /** * Admin Tools script services. @@ -43,9 +52,18 @@ @Unstable public class AdminToolsScriptService implements ScriptService { + @Inject + private Logger logger; + @Inject private AdminToolsManager adminToolsManager; + @Inject + private JobExecutor jobExecutor; + + @Inject + private Provider wikiContextProvider; + /** * Retrieve all the configuration information in a format given by the associated templates generated by the data * providers. @@ -63,9 +81,15 @@ public String getConfigurationData() * @param hint {@link String} representing the data provider * @return a {@link String} representing a specific template. */ - public String getConfigurationData(String hint) + public String getConfigurationData(String hint) throws ComponentLookupException { - return this.adminToolsManager.generateData(hint); + try { + return this.adminToolsManager.generateData(hint); + } catch (ComponentLookupException e) { + logger.error("Could not retrieve data for the given hint [{}]. Root cause is: [{}]", hint, + ExceptionUtils.getRootCauseMessage(e)); + throw e; + } } /** @@ -97,4 +121,38 @@ public String getFilesSection() { return this.adminToolsManager.getFilesSection(); } + + /** + * Check if an Admin Tools Health Check job for the wiki from where the request was made exists. If it does, return + * the job instance, else create a new Admin Tools health check request for the given wiki and start the execution. + * + * @return the asynchronous background job that will execute the request. + */ + public Job runHealthChecks() + { + try { + List requestId = this.getHealthCheckJobId(); + Job job = this.jobExecutor.getJob(requestId); + if (job == null) { + HealthCheckJobRequest healthCheckJobRequest = new HealthCheckJobRequest(requestId); + return this.jobExecutor.execute(HealthCheckJob.JOB_TYPE, healthCheckJobRequest); + } else { + return job; + } + } catch (Exception e) { + return null; + } + } + + /** + * Get the Health Check job id for the current wiki. + * + * @return Health check job id. + */ + public List getHealthCheckJobId() + { + XWikiContext wikiContext = wikiContextProvider.get(); + String wikiID = wikiContext.getWikiId(); + return List.of("adminTools", "healthCheck", wikiID); + } } diff --git a/application-admintools-default/src/main/resources/META-INF/components.txt b/application-admintools-default/src/main/resources/META-INF/components.txt index af01748c..a3f0e4c1 100644 --- a/application-admintools-default/src/main/resources/META-INF/components.txt +++ b/application-admintools-default/src/main/resources/META-INF/components.txt @@ -12,5 +12,19 @@ com.xwiki.admintools.internal.files.ImportantFilesManager com.xwiki.admintools.internal.configuration.AdminToolsConfigurationSource com.xwiki.admintools.internal.configuration.DefaultAdminToolsConfiguration com.xwiki.admintools.internal.AdminToolsEventListener +com.xwiki.admintools.internal.health.checks.configuration.ConfigurationDatabaseHealthCheck +com.xwiki.admintools.internal.health.checks.configuration.ConfigurationJavaHealthCheck +com.xwiki.admintools.internal.health.checks.configuration.ConfigurationOSHealthCheck +com.xwiki.admintools.internal.health.checks.security.ActiveEncodingHealthCheck +com.xwiki.admintools.internal.health.checks.security.ConfigurationEncodingHealthCheck +com.xwiki.admintools.internal.health.checks.security.FileEncodingHealthCheck +com.xwiki.admintools.internal.health.checks.security.LangEncodingHealthCheck +com.xwiki.admintools.internal.health.checks.performance.CPUHealthCheck +com.xwiki.admintools.internal.health.checks.performance.LogsSizeCheck +com.xwiki.admintools.internal.health.checks.performance.PhysicalMemoryHealthCheck +com.xwiki.admintools.internal.health.checks.performance.PhysicalSpaceHealthCheck +com.xwiki.admintools.internal.health.checks.memory.CacheMemoryHealthCheck +com.xwiki.admintools.internal.health.checks.memory.MemoryHealthCheck +com.xwiki.admintools.internal.health.job.HealthCheckJob com.xwiki.admintools.internal.rest.DefaultAdminToolsResource com.xwiki.admintools.internal.PingProvider diff --git a/application-admintools-default/src/main/resources/templates/configurationTemplate.vm b/application-admintools-default/src/main/resources/templates/configurationTemplate.vm index 45fb435a..21fcb8c9 100644 --- a/application-admintools-default/src/main/resources/templates/configurationTemplate.vm +++ b/application-admintools-default/src/main/resources/templates/configurationTemplate.vm @@ -24,12 +24,12 @@ #if ($configuration['serverFound'] == 'true')

$services.icon.renderHTML('world') - $escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.title'))

-

$escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.description'))

+ $escapetool.xml($services.localization.render('adminTools.dashboard.backend.title')) +

$escapetool.xml($services.localization.render('adminTools.dashboard.backend.description'))


  • - $escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.xwiki.version')): + $escapetool.xml($services.localization.render('adminTools.dashboard.backend.xwiki.version')): $configuration['xwikiVersion']
    • @@ -39,33 +39,33 @@
  • - $escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.java')): + $escapetool.xml($services.localization.render('adminTools.dashboard.backend.java')): $configuration['javaVersion']
  • - $escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.usedServer')) + $escapetool.xml($services.localization.render('adminTools.dashboard.backend.usedServer')) $configuration['usedServerName'] - $configuration['usedServerVersion']
  • -
  • $escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.os.legend')) +
  • $escapetool.xml($services.localization.render('adminTools.dashboard.backend.os.legend'))
      -
    • $escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.os.name')): +
    • $escapetool.xml($services.localization.render('adminTools.dashboard.backend.os.name')): $configuration['osName']
    • -
    • $escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.os.version')): +
    • $escapetool.xml($services.localization.render('adminTools.dashboard.backend.os.version')): $configuration['osVersion']
    • -
    • $escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.os.architecture')): +
    • $escapetool.xml($services.localization.render('adminTools.dashboard.backend.os.architecture')): $configuration['osArch']
  • #if ($configuration['databaseName'] != $null) -
  • $escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.usedDB')) +
  • $escapetool.xml($services.localization.render('adminTools.dashboard.backend.usedDB')) $configuration['databaseName'] - $configuration['databaseVersion']
  • #else #set($warningDatabaseMessage = $escapetool.xml( - $services.localization.render('adminTools.dashboard.section.backend.supportedDB.error')) + ':') + $services.localization.render('adminTools.dashboard.backend.supportedDB.error')) + ':') #set($warningDatabaseMessage = $warningDatabaseMessage + $stringtool.join($services.admintools.getSupportedDatabases(), ', '))
  • $escapetool.xml( - $services.localization.render('adminTools.dashboard.section.backend.usedDB')) #warning($warningDatabaseMessage) + $services.localization.render('adminTools.dashboard.backend.usedDB')) #warning($warningDatabaseMessage)
  • #end
@@ -73,9 +73,9 @@ #viewLastNLinesMoldal("configuration") #else #set($warningMessage = - $escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.configuration.error'))+ '
') + $escapetool.xml($services.localization.render('adminTools.dashboard.backend.configuration.error'))+ '
') #set($warningMessage = $warningMessage + - $escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.supportedServers.error')) + ':' + $escapetool.xml($services.localization.render('adminTools.dashboard.backend.supportedServers.error')) + ':' + $stringtool.join($services.admintools.getSupportedServers(), ', ')) #warning($warningMessage) #end diff --git a/application-admintools-default/src/main/resources/templates/filesSectionTemplate.vm b/application-admintools-default/src/main/resources/templates/filesSectionTemplate.vm index 202b696f..e2d8a287 100644 --- a/application-admintools-default/src/main/resources/templates/filesSectionTemplate.vm +++ b/application-admintools-default/src/main/resources/templates/filesSectionTemplate.vm @@ -25,27 +25,27 @@ #if ($found)

$services.icon.renderHTML('download') - $escapetool.xml($services.localization.render('adminTools.dashboard.section.download.title'))

-

$escapetool.xml($services.localization.render('adminTools.dashboard.section.download.description'))

+ $escapetool.xml($services.localization.render('adminTools.dashboard.download.title')) +

$escapetool.xml($services.localization.render('adminTools.dashboard.download.description'))


- #warning($escapetool.xml($services.localization.render('adminTools.dashboard.section.download.warning'))) + #warning($escapetool.xml($services.localization.render('adminTools.dashboard.download.warning')))
#viewLastNLinesMoldal("files") #downloadArchiveModal() #else #set($warningMessage = - $escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.configuration.error'))+ '
') + $escapetool.xml($services.localization.render('adminTools.dashboard.backend.configuration.error'))+ '
') #set($warningMessage = $warningMessage + - $escapetool.xml($services.localization.render('adminTools.dashboard.section.backend.supportedServers.error')) + ':' + $escapetool.xml($services.localization.render('adminTools.dashboard.backend.supportedServers.error')) + ': ' + $stringtool.join($services.admintools.getSupportedServers(), ', ')) #warning($warningMessage) #end diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/AdminToolsEventListenerTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/AdminToolsEventListenerTest.java index 306e4fbb..243168e3 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/AdminToolsEventListenerTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/AdminToolsEventListenerTest.java @@ -44,16 +44,16 @@ import static org.mockito.Mockito.when; @ComponentTest -public class AdminToolsEventListenerTest +class AdminToolsEventListenerTest { private final List SPACE = Arrays.asList("AdminTools", "Code"); - @Mock - private XWikiDocument xWikiDocument; - @InjectMockComponents private AdminToolsEventListener adminToolsEventListener; + @Mock + private XWikiDocument xWikiDocument; + @MockComponent private WikiDescriptorManager wikiDescriptorManager; diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/configuration/DefaultAdminToolsConfigurationTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/configuration/DefaultAdminToolsConfigurationTest.java index 69ce6cab..2cd27dde 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/configuration/DefaultAdminToolsConfigurationTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/configuration/DefaultAdminToolsConfigurationTest.java @@ -29,7 +29,6 @@ import org.xwiki.test.junit5.mockito.InjectMockComponents; import org.xwiki.test.junit5.mockito.MockComponent; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; @@ -39,7 +38,7 @@ * @version $Id$ */ @ComponentTest -public class DefaultAdminToolsConfigurationTest +class DefaultAdminToolsConfigurationTest { @InjectMockComponents private DefaultAdminToolsConfiguration defaultAdminToolsConfiguration; diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/ConfigurationDataProviderTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/ConfigurationDataProviderTest.java index 2de89566..dd2993f3 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/ConfigurationDataProviderTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/ConfigurationDataProviderTest.java @@ -42,8 +42,8 @@ import com.xpn.xwiki.XWiki; import com.xpn.xwiki.XWikiContext; import com.xwiki.admintools.ServerIdentifier; -import com.xwiki.admintools.internal.data.identifiers.CurrentServer; import com.xwiki.admintools.internal.PingProvider; +import com.xwiki.admintools.internal.data.identifiers.CurrentServer; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -58,12 +58,15 @@ * @version $Id$ */ @ComponentTest -public class ConfigurationDataProviderTest +class ConfigurationDataProviderTest { - static Map defaultJson; + private static Map defaultJson; private final String templatePath = "configurationTemplate.vm"; + @InjectMockComponents + private ConfigurationDataProvider configurationDataProvider; + @MockComponent private Provider xcontextProvider; @@ -73,9 +76,6 @@ public class ConfigurationDataProviderTest @Mock private XWiki wiki; - @InjectMockComponents - private ConfigurationDataProvider configurationDataProvider; - @MockComponent private CurrentServer currentServer; diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/SecurityDataProviderTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/SecurityDataProviderTest.java index 2a969f18..fd264b15 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/SecurityDataProviderTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/SecurityDataProviderTest.java @@ -54,18 +54,18 @@ * @version $Id$ */ @ComponentTest -public class SecurityDataProviderTest +class SecurityDataProviderTest { - static Map defaultJson; + private static Map defaultJson; private final String templatePath = "securityTemplate.vm"; - @MockComponent - private Provider xcontextProvider; - @InjectMockComponents private SecurityDataProvider securityDataProvider; + @MockComponent + private Provider xcontextProvider; + @MockComponent @Named("xwikicfg") private ConfigurationSource configurationSource; diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/CurrentServerTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/CurrentServerTest.java index 7aad17ae..89f67794 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/CurrentServerTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/CurrentServerTest.java @@ -45,7 +45,7 @@ * @version $Id$ */ @ComponentTest -public class CurrentServerTest +class CurrentServerTest { @InjectMockComponents private CurrentServer currentServer; diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/TomcatIdentifierTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/TomcatIdentifierTest.java index f14994ae..7630f039 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/TomcatIdentifierTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/TomcatIdentifierTest.java @@ -43,7 +43,7 @@ * @version $Id$ */ @ComponentTest -public class TomcatIdentifierTest +class TomcatIdentifierTest { @InjectMockComponents private TomcatIdentifier tomcatIdentifier; diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/ImportantFilesManagerTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/ImportantFilesManagerTest.java index 0b391a2b..a90e1d00 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/ImportantFilesManagerTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/ImportantFilesManagerTest.java @@ -20,19 +20,18 @@ package com.xwiki.admintools.internal.files; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.zip.ZipOutputStream; -import javax.inject.Provider; +import javax.inject.Named; import javax.script.ScriptContext; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.slf4j.Logger; +import org.xwiki.component.manager.ComponentManager; import org.xwiki.component.util.ReflectionUtils; import org.xwiki.script.ScriptContextManager; import org.xwiki.template.TemplateManager; @@ -49,12 +48,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.AdditionalMatchers.aryEq; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -64,16 +59,15 @@ * @version $Id$ */ @ComponentTest -public class ImportantFilesManagerTest +class ImportantFilesManagerTest { private final String templatePath = "filesSectionTemplate.vm"; + private final Map params = Map.of("input", new String[] { "good_input" }); + @InjectMockComponents private ImportantFilesManager importantFilesManager; - @MockComponent - private Provider> dataResources; - @MockComponent private DataResource archiverDataResource; @@ -92,33 +86,33 @@ public class ImportantFilesManagerTest @MockComponent private ServerIdentifier serverIdentifier; + @MockComponent + @Named("context") + private ComponentManager contextComponentManager; + @Mock private ScriptContext scriptContext; @Mock private Logger logger; - private final Map params = Map.of("input", new String[]{"good_input"}); + @BeforeEach + void setUp() throws Exception + { + when(archiverDataResource.getByteData(params)).thenReturn(new byte[] { 2 }); + when(contextComponentManager.getInstance(DataResource.class, "data_resource_identifier")).thenReturn( + archiverDataResource); + } @Test void getFile() throws Exception { - List dataResourceList = new ArrayList<>(); - dataResourceList.add(archiverDataResource); - when(dataResources.get()).thenReturn(dataResourceList); - when(archiverDataResource.getIdentifier()).thenReturn("data_resource_identifier"); - when(archiverDataResource.getByteData(params)).thenReturn(new byte[] { 2 }); - assertArrayEquals(new byte[] { 2 }, importantFilesManager.getFile("data_resource_identifier", params)); } @Test - void getFileResourceNotFound() + void getFileResourceNotFound() throws Exception { - List dataResourceList = new ArrayList<>(); - dataResourceList.add(archiverDataResource); - when(dataResources.get()).thenReturn(dataResourceList); - when(archiverDataResource.getIdentifier()).thenReturn("data_resource_identifier"); Exception exception = assertThrows(Exception.class, () -> { importantFilesManager.getFile("data_resource_identifier_invalid", params); }); @@ -129,10 +123,6 @@ void getFileResourceNotFound() @Test void getFileDataResourceError() throws Exception { - List dataResourceList = new ArrayList<>(); - dataResourceList.add(archiverDataResource); - when(dataResources.get()).thenReturn(dataResourceList); - when(archiverDataResource.getIdentifier()).thenReturn("data_resource_identifier"); when(archiverDataResource.getByteData(params)).thenThrow(new IOException("IO Error")); Exception exception = assertThrows(Exception.class, () -> { importantFilesManager.getFile("data_resource_identifier", params); @@ -152,13 +142,8 @@ void downloadMultipleFiles() throws Exception filters.put("from", new String[] { "" }); filters.put("to", new String[] { "" }); - List dataResourceList = new ArrayList<>(); - dataResourceList.add(archiverDataResource); - dataResourceList.add(archiverLogsDataResource); - - when(dataResources.get()).thenReturn(dataResourceList); - when(archiverDataResource.getIdentifier()).thenReturn("data_resource_identifier"); - when(archiverLogsDataResource.getIdentifier()).thenReturn(LogsDataResource.HINT); + when(contextComponentManager.getInstance(DataResource.class, LogsDataResource.HINT)).thenReturn( + archiverLogsDataResource); importantFilesManager.getFilesArchive(request); verify(archiverDataResource).addZipEntry(any(ZipOutputStream.class), any()); @@ -171,32 +156,22 @@ void downloadMultipleFilesNoArchiverFound() throws Exception String[] files = { "data_resource_identifier_invalid", LogsDataResource.HINT }; Map request = new HashMap<>(); request.put("files", files); - List dataResourceList = new ArrayList<>(); - dataResourceList.add(archiverDataResource); - when(dataResources.get()).thenReturn(dataResourceList); - when(archiverDataResource.getIdentifier()).thenReturn("data_resource_identifier"); importantFilesManager.getFilesArchive(request); verify(archiverDataResource, never()).addZipEntry(any(ZipOutputStream.class), any()); } @Test - void downloadMultipleFilesInvalidRequest() + void downloadMultipleFilesInvalidRequest() throws Exception { - String[] files = { "data_resource_identifier", LogsDataResource.HINT }; + String[] files = { "invalid_hint1", "invalid_hint2" }; Map request = new HashMap<>(); request.put("files", files); - List dataResourceList = new ArrayList<>(); - dataResourceList.add(archiverDataResource); - dataResourceList.add(archiverLogsDataResource); - - when(dataResources.get()).thenReturn(dataResourceList); - when(archiverDataResource.getIdentifier()).thenReturn("data_resource_identifier"); - Exception exception = assertThrows(Exception.class, () -> { - importantFilesManager.getFilesArchive(request); - }); - - assertEquals("Error while generating the files archive.", exception.getMessage()); + when(contextComponentManager.getInstance(DataResource.class, LogsDataResource.HINT)).thenReturn( + archiverLogsDataResource); + importantFilesManager.getFilesArchive(request); + verify(archiverDataResource, never()).addZipEntry(any(ZipOutputStream.class), any()); + verify(archiverLogsDataResource, never()).addZipEntry(any(ZipOutputStream.class), any()); } @Test diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/DataProvidersDataResourceTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/DataProvidersDataResourceTest.java index a5ccd9ea..42965cf0 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/DataProvidersDataResourceTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/DataProvidersDataResourceTest.java @@ -53,14 +53,14 @@ * @version $Id$ */ @ComponentTest -public class DataProvidersDataResourceTest +class DataProvidersDataResourceTest { - @Mock - ZipOutputStream zipOutputStream; - @InjectMockComponents private DataProvidersDataResource dataProviderResource; + @Mock + private ZipOutputStream zipOutputStream; + @MockComponent private Provider> dataProviders; @@ -104,7 +104,8 @@ void getByteDataThrowError() throws Exception Exception exception = assertThrows(Exception.class, () -> { this.dataProviderResource.getByteData(null); }); - assertEquals("Error while getting JSON data for [data_provider_identifier] DataProvider.", exception.getMessage()); + assertEquals("Error while getting JSON data for [data_provider_identifier] DataProvider.", + exception.getMessage()); } @Test diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/LogsDataResourceTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/LogsDataResourceTest.java index 7d3baf8d..816bf451 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/LogsDataResourceTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/LogsDataResourceTest.java @@ -70,16 +70,16 @@ * @version $Id$ */ @ComponentTest -public class LogsDataResourceTest +class LogsDataResourceTest { private final Map params = Map.of("noLines", new String[] { "44" }); - @Mock - ZipOutputStream zipOutputStream; - @InjectMockComponents private LogsDataResource logsDataResource; + @Mock + private ZipOutputStream zipOutputStream; + @Mock private Logger logger; @@ -203,8 +203,7 @@ void getByteDataNullInput() throws IOException readLines(1000); - assertArrayEquals(String.join("\n", logLines).getBytes(), - logsDataResource.getByteData(null)); + assertArrayEquals(String.join("\n", logLines).getBytes(), logsDataResource.getByteData(null)); } @Test @@ -215,8 +214,7 @@ void getByteDataNullNoLines() throws IOException Map params = Map.of("noLines", new String[] { null }); readLines(1000); - assertArrayEquals(String.join("\n", logLines).getBytes(), - logsDataResource.getByteData(params)); + assertArrayEquals(String.join("\n", logLines).getBytes(), logsDataResource.getByteData(params)); } @Test @@ -237,8 +235,8 @@ void addZipEntrySuccessWithFilters() throws IOException when(serverIdentifier.getLogsPattern()).thenReturn(Pattern.compile("\\d{4}-\\d{2}-\\d{2}")); Map filters = new HashMap<>(); - filters.put("from", new String[]{"06-10-2023"}); - filters.put("to", new String[]{"07-10-2023"}); + filters.put("from", new String[] { "06-10-2023" }); + filters.put("to", new String[] { "07-10-2023" }); readLines(400); logsDataResource.addZipEntry(zipOutputStream, filters); byte[] buff = new byte[2048]; @@ -259,8 +257,8 @@ void addZipEntryFilesOutOfFiltersRange() throws IOException when(xWiki.getXWikiPreference("dateformat", "dd-MM-yyyy", wikiContext)).thenReturn("dd yy MM"); Map filters = new HashMap<>(); - filters.put("from", new String[]{"10 23 10"}); - filters.put("to", new String[]{ null }); + filters.put("from", new String[] { "10 23 10" }); + filters.put("to", new String[] { null }); logsDataResource.addZipEntry(zipOutputStream, filters); verify(zipOutputStream, never()).closeEntry(); @@ -276,8 +274,8 @@ void addZipEntryDateParseError() when(serverIdentifier.getLogsFolderPath()).thenReturn(logsDir.getAbsolutePath()); when(serverIdentifier.getLogsPattern()).thenReturn(Pattern.compile("\\bserver\\b")); Map filters = new HashMap<>(); - filters.put("from", new String[]{"2023-10-03"}); - filters.put("to", new String[]{"2023-10-05"}); + filters.put("from", new String[] { "2023-10-03" }); + filters.put("to", new String[] { "2023-10-05" }); logsDataResource.addZipEntry(zipOutputStream, filters); verify(logger).warn("Failed to get logs. Root cause is: [{}]", "DateTimeParseException: Text 'server' could not be parsed at index 0"); @@ -290,8 +288,8 @@ void addZipEntryPatternNotFound() throws IOException when(serverIdentifier.getLogsFolderPath()).thenReturn(logsDir.getAbsolutePath()); when(serverIdentifier.getLogsPattern()).thenReturn(Pattern.compile("\\d{4}_\\d{2}_\\d{2}")); Map filters = new HashMap<>(); - filters.put("from", new String[]{"2023-10-03"}); - filters.put("to", new String[]{"2023-10-05"}); + filters.put("from", new String[] { "2023-10-03" }); + filters.put("to", new String[] { "2023-10-05" }); logsDataResource.addZipEntry(zipOutputStream, filters); verify(zipOutputStream, never()).closeEntry(); } diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiConfigFileDataResourceTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiConfigFileDataResourceTest.java index 3ae1b1db..920a4833 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiConfigFileDataResourceTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiConfigFileDataResourceTest.java @@ -62,7 +62,7 @@ * @version $Id$ */ @ComponentTest -public class XWikiConfigFileDataResourceTest +class XWikiConfigFileDataResourceTest { @InjectMockComponents private XWikiConfigFileDataResource configFileDataResource; @@ -194,8 +194,7 @@ void addZipEntryGetByteFail() throws Exception configFileDataResource.addZipEntry(zipOutputStream, null); verify(zipOutputStream, never()).write(any(), eq(0), anyInt()); verify(logger).warn("Could not add {} to the archive. Root cause is: [{}]", "xwiki.cfg", - "FileNotFoundException: " + cfgDir2.getAbsolutePath() + "/xwiki.cfg (No such file or " - + "directory)"); + "FileNotFoundException: " + cfgDir2.getAbsolutePath() + "/xwiki.cfg (No such file or " + "directory)"); } private byte[] readLines() throws IOException diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiPropertiesFileDataResourceTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiPropertiesFileDataResourceTest.java index cf020768..e233a548 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiPropertiesFileDataResourceTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiPropertiesFileDataResourceTest.java @@ -62,7 +62,7 @@ * @version $Id$ */ @ComponentTest -public class XWikiPropertiesFileDataResourceTest +class XWikiPropertiesFileDataResourceTest { @InjectMockComponents private XWikiPropertiesFileDataResource propertiesFileDataResource; diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationDatabaseHealthCheckTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationDatabaseHealthCheckTest.java new file mode 100644 index 00000000..2624b548 --- /dev/null +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationDatabaseHealthCheckTest.java @@ -0,0 +1,103 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.configuration; + +import java.util.List; +import java.util.Map; + +import javax.inject.Named; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.slf4j.Logger; +import org.xwiki.component.manager.ComponentLookupException; +import org.xwiki.component.util.ReflectionUtils; +import org.xwiki.test.annotation.BeforeComponent; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; + +import com.xwiki.admintools.DataProvider; +import com.xwiki.admintools.internal.data.ConfigurationDataProvider; +import com.xwiki.admintools.internal.data.identifiers.CurrentServer; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ComponentTest +class ConfigurationDatabaseHealthCheckTest +{ + @MockComponent + @Named(ConfigurationDataProvider.HINT) + private static DataProvider configurationDataProvider; + + @InjectMockComponents + private ConfigurationDatabaseHealthCheck databaseHealthCheck; + + @MockComponent + private CurrentServer currentServer; + + @Mock + private Logger logger; + + @BeforeComponent + static void setUp() throws Exception + { + Map jsonResponse = Map.of("databaseName", "MYSQL"); + when(configurationDataProvider.getDataAsJSON()).thenReturn(jsonResponse); + } + + @BeforeEach + void beforeEach() throws ComponentLookupException + { + List supportedDatabases = List.of("MySQL", "HSQL"); + when(currentServer.getSupportedDBs()).thenReturn(supportedDatabases); + when(logger.isWarnEnabled()).thenReturn(true); + ReflectionUtils.setFieldValue(databaseHealthCheck, "logger", this.logger); + } + + @Test + void check() + { + assertEquals("adminTools.dashboard.healthcheck.database.info", databaseHealthCheck.check().getMessage()); + } + + @Test + void checkNullJSON() throws Exception + { + when(configurationDataProvider.getDataAsJSON()).thenThrow(new Exception("error while generating the json")); + + assertEquals("adminTools.dashboard.healthcheck.database.warn", databaseHealthCheck.check().getMessage()); + verify(logger).warn("Database not found!"); + } + + @Test + void checkDatabaseNotCompatible() throws Exception + { + Map jsonResponse = Map.of("databaseName", "NOT_COMPATIBLE"); + when(configurationDataProvider.getDataAsJSON()).thenReturn(jsonResponse); + + assertEquals("adminTools.dashboard.healthcheck.database.notSupported", + databaseHealthCheck.check().getMessage()); + verify(logger).error("Used database is not supported!"); + } +} diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationJavaHealthCheckTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationJavaHealthCheckTest.java new file mode 100644 index 00000000..82ed504d --- /dev/null +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationJavaHealthCheckTest.java @@ -0,0 +1,89 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.configuration; + +import java.util.Map; + +import javax.inject.Named; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.slf4j.Logger; +import org.xwiki.component.manager.ComponentLookupException; +import org.xwiki.component.util.ReflectionUtils; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; + +import com.xwiki.admintools.DataProvider; +import com.xwiki.admintools.internal.data.ConfigurationDataProvider; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ComponentTest +class ConfigurationJavaHealthCheckTest +{ + @MockComponent + @Named(ConfigurationDataProvider.HINT) + private static DataProvider dataProvider; + + @InjectMockComponents + private ConfigurationJavaHealthCheck javaHealthCheck; + + @Mock + private Logger logger; + + @BeforeEach + void beforeEach() throws Exception + { + when(logger.isWarnEnabled()).thenReturn(true); + ReflectionUtils.setFieldValue(javaHealthCheck, "logger", this.logger); + + Map jsonResponse = Map.of("javaVersion", "11.0.2", "xwikiVersion", "14.10.2"); + when(dataProvider.getDataAsJSON()).thenReturn(jsonResponse); + } + + @Test + void check() + { + assertEquals("adminTools.dashboard.healthcheck.java.info", javaHealthCheck.check().getMessage()); + } + + @Test + void checkNullJSON() throws Exception + { + when(dataProvider.getDataAsJSON()).thenThrow(new Exception("error while generating the json")); + + assertEquals("adminTools.dashboard.healthcheck.java.warn", javaHealthCheck.check().getMessage()); + verify(logger).warn("Java version not found!"); + } + + @Test + void checkJavaVersionIncompatible() throws Exception + { + Map jsonResponse = Map.of("javaVersion", "11.0.2", "xwikiVersion", "6.10.2"); + when(dataProvider.getDataAsJSON()).thenReturn(jsonResponse); + assertEquals("adminTools.dashboard.healthcheck.java.error", javaHealthCheck.check().getMessage()); + verify(logger).error("Java version is not compatible with the current XWiki installation!"); + } +} diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationOSHealthCheckTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationOSHealthCheckTest.java new file mode 100644 index 00000000..8c7071cd --- /dev/null +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/configuration/ConfigurationOSHealthCheckTest.java @@ -0,0 +1,87 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.configuration; + +import java.util.Map; + +import javax.inject.Named; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.slf4j.Logger; +import org.xwiki.component.manager.ComponentLookupException; +import org.xwiki.component.util.ReflectionUtils; +import org.xwiki.test.annotation.BeforeComponent; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; + +import com.xwiki.admintools.DataProvider; +import com.xwiki.admintools.internal.data.ConfigurationDataProvider; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ComponentTest +class ConfigurationOSHealthCheckTest +{ + @MockComponent + @Named(ConfigurationDataProvider.HINT) + private static DataProvider dataProvider; + + @InjectMockComponents + private ConfigurationOSHealthCheck osHealthCheck; + + @Mock + private Logger logger; + + @BeforeComponent + static void setUp() throws Exception + { + Map jsonResponse = + Map.of("osName", "testDBName", "osVersion", "os_version", "osArch", "os_arch"); + when(dataProvider.getDataAsJSON()).thenReturn(jsonResponse); + } + + @BeforeEach + void beforeEach() throws ComponentLookupException + { + when(logger.isWarnEnabled()).thenReturn(true); + ReflectionUtils.setFieldValue(osHealthCheck, "logger", this.logger); + } + + @Test + void check() + { + assertEquals("adminTools.dashboard.healthcheck.os.info", osHealthCheck.check().getMessage()); + } + + @Test + void checkNullJSON() throws Exception + { + when(dataProvider.getDataAsJSON()).thenThrow(new Exception("error while generating the json")); + + assertEquals("adminTools.dashboard.healthcheck.os.warn", osHealthCheck.check().getMessage()); + verify(logger).warn("There has been an error while gathering OS info!"); + } +} diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/memory/CacheMemoryHealthCheckTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/memory/CacheMemoryHealthCheckTest.java new file mode 100644 index 00000000..f63ff7dd --- /dev/null +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/memory/CacheMemoryHealthCheckTest.java @@ -0,0 +1,82 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.memory; + +import javax.inject.Named; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.slf4j.Logger; +import org.xwiki.component.util.ReflectionUtils; +import org.xwiki.configuration.ConfigurationSource; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ComponentTest +class CacheMemoryHealthCheckTest +{ + @InjectMockComponents + private CacheMemoryHealthCheck cacheMemoryHealthCheck; + + @MockComponent + @Named("xwikicfg") + private ConfigurationSource configurationSource; + + @Mock + private Logger logger; + + @BeforeEach + void beforeEach() + { + when(logger.isWarnEnabled()).thenReturn(true); + ReflectionUtils.setFieldValue(cacheMemoryHealthCheck, "logger", this.logger); + + } + + @Test + void check() + { + when(configurationSource.getProperty("xwiki.store.cache.capacity")).thenReturn("1000"); + assertEquals("adminTools.dashboard.healthcheck.memory.cache.info", cacheMemoryHealthCheck.check().getMessage()); + } + + @Test + void checkCacheLow() + { + when(configurationSource.getProperty("xwiki.store.cache.capacity")).thenReturn("400"); + assertEquals("adminTools.dashboard.healthcheck.memory.cache.low", cacheMemoryHealthCheck.check().getMessage()); + verify(logger).warn("Store cache capacity is set to [{}].", "400"); + } + + + @Test + void checkCacheNotDefined() + { + when(configurationSource.getProperty("xwiki.store.cache.capacity")).thenReturn(null); + assertEquals("adminTools.dashboard.healthcheck.memory.cache.null", cacheMemoryHealthCheck.check().getMessage()); + verify(logger).warn("Store cache capacity not defined. Set by default at 500."); + } +} diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/memory/MemoryHealthCheckTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/memory/MemoryHealthCheckTest.java new file mode 100644 index 00000000..e8e3e5ff --- /dev/null +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/memory/MemoryHealthCheckTest.java @@ -0,0 +1,110 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.memory; + +import javax.inject.Provider; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.slf4j.Logger; +import org.xwiki.component.util.ReflectionUtils; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; + +import com.xpn.xwiki.XWiki; +import com.xpn.xwiki.XWikiContext; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ComponentTest +class MemoryHealthCheckTest +{ + @InjectMockComponents + private MemoryHealthCheck memoryHealthCheck; + + @MockComponent + private Provider xcontextProvider; + + @MockComponent + private XWikiContext context; + + @Mock + private XWiki xwiki; + + @Mock + private Logger logger; + + @BeforeEach + void beforeEach() + { + when(logger.isWarnEnabled()).thenReturn(true); + ReflectionUtils.setFieldValue(memoryHealthCheck, "logger", this.logger); + + when(xcontextProvider.get()).thenReturn(context); + when(context.getWiki()).thenReturn(xwiki); + } + + @Test + void check() + { + when(xwiki.maxMemory()).thenReturn((long) (8 * Math.pow(1024, 3))); + when(xwiki.totalMemory()).thenReturn((long) (1.5 * Math.pow(1024, 3))); + when(xwiki.freeMemory()).thenReturn((long) (0.5 * Math.pow(1024, 3))); + + assertEquals("adminTools.dashboard.healthcheck.memory.info", memoryHealthCheck.check().getMessage()); + } + + @Test + void checkInsufficientMaxMemory() + { + when(xwiki.maxMemory()).thenReturn((long) (0.8 * Math.pow(1024, 3))); + when(xwiki.totalMemory()).thenReturn((long) (0.5 * Math.pow(1024, 3))); + when(xwiki.freeMemory()).thenReturn((long) (0.2 * Math.pow(1024, 3))); + + assertEquals("adminTools.dashboard.healthcheck.memory.maxcapacity.error", + memoryHealthCheck.check().getMessage()); + } + + @Test + void checkCriticalFreeMemory() + { + when(xwiki.maxMemory()).thenReturn((long) (1.7 * Math.pow(1024, 3))); + when(xwiki.totalMemory()).thenReturn((long) (1.5 * Math.pow(1024, 3))); + when(xwiki.freeMemory()).thenReturn((long) (0.2 * Math.pow(1024, 3))); + + assertEquals("adminTools.dashboard.healthcheck.memory.free.error", memoryHealthCheck.check().getMessage()); + logger.error("JVM instance has only [{}]MB free memory left!", 409.6001f); + } + + @Test + void checkLowFreeMemory() + { + when(xwiki.maxMemory()).thenReturn((long) (2 * Math.pow(1024, 3))); + when(xwiki.totalMemory()).thenReturn((long) (1.5 * Math.pow(1024, 3))); + when(xwiki.freeMemory()).thenReturn((long) (0.2 * Math.pow(1024, 3))); + + assertEquals("adminTools.dashboard.healthcheck.memory.free.warn", memoryHealthCheck.check().getMessage()); + verify(logger).warn("Instance memory is running low. Currently only [{}]MB free left.", 716.80005f); + } +} diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/security/ActiveEncodingHealthCheckTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/security/ActiveEncodingHealthCheckTest.java new file mode 100644 index 00000000..80519212 --- /dev/null +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/security/ActiveEncodingHealthCheckTest.java @@ -0,0 +1,92 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.security; + +import java.util.Map; + +import javax.inject.Named; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.slf4j.Logger; +import org.xwiki.component.util.ReflectionUtils; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; + +import com.xwiki.admintools.DataProvider; +import com.xwiki.admintools.internal.data.SecurityDataProvider; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ComponentTest +class ActiveEncodingHealthCheckTest +{ + @InjectMockComponents + private ActiveEncodingHealthCheck activeEncodingHealthCheck; + + @MockComponent + @Named(SecurityDataProvider.HINT) + private DataProvider dataProvider; + + @Mock + private Logger logger; + + @BeforeEach + void beforeEach() throws Exception + { + when(logger.isWarnEnabled()).thenReturn(true); + ReflectionUtils.setFieldValue(activeEncodingHealthCheck, "logger", this.logger); + + when(dataProvider.getIdentifier()).thenReturn(SecurityDataProvider.HINT); + Map jsonResponse = Map.of("activeEncoding", "UTF8"); + when(dataProvider.getDataAsJSON()).thenReturn(jsonResponse); + } + + @Test + void check() + { + assertEquals("adminTools.dashboard.healthcheck.security.xwiki.active.info", + activeEncodingHealthCheck.check().getMessage()); + } + + @Test + void checkNullJSON() throws Exception + { + when(dataProvider.getDataAsJSON()).thenThrow(new Exception("error while generating the json")); + + assertEquals("adminTools.dashboard.healthcheck.security.xwiki.active.notFound", + activeEncodingHealthCheck.check().getMessage()); + logger.warn("Active encoding could not be detected!"); + } + + @Test + void checkUnsafeEncoding() throws Exception + { + Map jsonResponse = Map.of("activeEncoding", "ISO-8859-1"); + when(dataProvider.getDataAsJSON()).thenReturn(jsonResponse); + assertEquals("adminTools.dashboard.healthcheck.security.xwiki.active.warn", + activeEncodingHealthCheck.check().getMessage()); + verify(logger).warn("[{}] encoding is [{}], but should be UTF-8!", "XWiki active", "ISO-8859-1"); + } +} diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/security/ConfigurationEncodingHealthCheckTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/security/ConfigurationEncodingHealthCheckTest.java new file mode 100644 index 00000000..72e12ccd --- /dev/null +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/security/ConfigurationEncodingHealthCheckTest.java @@ -0,0 +1,92 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.security; + +import java.util.Map; + +import javax.inject.Named; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.slf4j.Logger; +import org.xwiki.component.util.ReflectionUtils; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; + +import com.xwiki.admintools.DataProvider; +import com.xwiki.admintools.internal.data.SecurityDataProvider; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ComponentTest +class ConfigurationEncodingHealthCheckTest +{ + @InjectMockComponents + private ConfigurationEncodingHealthCheck configurationEncodingHealthCheck; + + @MockComponent + @Named(SecurityDataProvider.HINT) + private DataProvider dataProvider; + + @Mock + private Logger logger; + + @BeforeEach + void beforeEach() throws Exception + { + when(logger.isWarnEnabled()).thenReturn(true); + ReflectionUtils.setFieldValue(configurationEncodingHealthCheck, "logger", this.logger); + + when(dataProvider.getIdentifier()).thenReturn(SecurityDataProvider.HINT); + Map jsonResponse = Map.of("configurationEncoding", "UTF8"); + when(dataProvider.getDataAsJSON()).thenReturn(jsonResponse); + } + + @Test + void check() + { + assertEquals("adminTools.dashboard.healthcheck.security.xwiki.config.info", + configurationEncodingHealthCheck.check().getMessage()); + } + + @Test + void checkNullJSON() throws Exception + { + when(dataProvider.getDataAsJSON()).thenThrow(new Exception("error while generating the json")); + + assertEquals("adminTools.dashboard.healthcheck.security.xwiki.config.notFound", + configurationEncodingHealthCheck.check().getMessage()); + logger.warn("Configuration encoding could not be detected!"); + } + + @Test + void checkUnsafeEncoding() throws Exception + { + Map jsonResponse = Map.of("configurationEncoding", "ISO-8859-1"); + when(dataProvider.getDataAsJSON()).thenReturn(jsonResponse); + assertEquals("adminTools.dashboard.healthcheck.security.xwiki.config.warn", + configurationEncodingHealthCheck.check().getMessage()); + verify(logger).warn("[{}] encoding is [{}], but should be UTF-8!", "XWiki configuration", "ISO-8859-1"); + } +} diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/security/FileEncodingHealthCheckTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/security/FileEncodingHealthCheckTest.java new file mode 100644 index 00000000..c99808a4 --- /dev/null +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/security/FileEncodingHealthCheckTest.java @@ -0,0 +1,92 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.security; + +import java.util.Map; + +import javax.inject.Named; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.slf4j.Logger; +import org.xwiki.component.util.ReflectionUtils; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; + +import com.xwiki.admintools.DataProvider; +import com.xwiki.admintools.internal.data.SecurityDataProvider; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ComponentTest +class FileEncodingHealthCheckTest +{ + @InjectMockComponents + private FileEncodingHealthCheck fileEncodingHealthCheck; + + @MockComponent + @Named(SecurityDataProvider.HINT) + private DataProvider dataProvider; + + @Mock + private Logger logger; + + @BeforeEach + void beforeEach() throws Exception + { + when(logger.isWarnEnabled()).thenReturn(true); + ReflectionUtils.setFieldValue(fileEncodingHealthCheck, "logger", this.logger); + + when(dataProvider.getIdentifier()).thenReturn(SecurityDataProvider.HINT); + Map jsonResponse = Map.of("fileEncoding", "UTF8"); + when(dataProvider.getDataAsJSON()).thenReturn(jsonResponse); + } + + @Test + void check() + { + assertEquals("adminTools.dashboard.healthcheck.security.system.file.info", + fileEncodingHealthCheck.check().getMessage()); + } + + @Test + void checkNullJSON() throws Exception + { + when(dataProvider.getDataAsJSON()).thenThrow(new Exception("error while generating the json")); + + assertEquals("adminTools.dashboard.healthcheck.security.system.file.notFound", + fileEncodingHealthCheck.check().getMessage()); + logger.warn("File encoding could not be detected!"); + } + + @Test + void checkUnsafeEncoding() throws Exception + { + Map jsonResponse = Map.of("fileEncoding", "ISO-8859-1"); + when(dataProvider.getDataAsJSON()).thenReturn(jsonResponse); + assertEquals("adminTools.dashboard.healthcheck.security.system.file.warn", + fileEncodingHealthCheck.check().getMessage()); + verify(logger).warn("[{}] encoding is [{}], but should be UTF-8!", "System file", "ISO-8859-1"); + } +} diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/security/LangEncodingHealthCheckTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/security/LangEncodingHealthCheckTest.java new file mode 100644 index 00000000..c4b59c90 --- /dev/null +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/checks/security/LangEncodingHealthCheckTest.java @@ -0,0 +1,92 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.checks.security; + +import java.util.Map; + +import javax.inject.Named; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.slf4j.Logger; +import org.xwiki.component.util.ReflectionUtils; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; + +import com.xwiki.admintools.DataProvider; +import com.xwiki.admintools.internal.data.SecurityDataProvider; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ComponentTest +class LangEncodingHealthCheckTest +{ + @InjectMockComponents + private LangEncodingHealthCheck langEncodingHealthCheck; + + @MockComponent + @Named(SecurityDataProvider.HINT) + private DataProvider dataProvider; + + @Mock + private Logger logger; + + @BeforeEach + void beforeEach() throws Exception + { + when(logger.isWarnEnabled()).thenReturn(true); + ReflectionUtils.setFieldValue(langEncodingHealthCheck, "logger", this.logger); + + when(dataProvider.getIdentifier()).thenReturn(SecurityDataProvider.HINT); + Map jsonResponse = Map.of("LANG", "en.UTF8"); + when(dataProvider.getDataAsJSON()).thenReturn(jsonResponse); + } + + @Test + void check() + { + assertEquals("adminTools.dashboard.healthcheck.security.system.lang.info", + langEncodingHealthCheck.check().getMessage()); + } + + @Test + void checkNullJSON() throws Exception + { + when(dataProvider.getDataAsJSON()).thenThrow(new Exception("error while generating the json")); + + assertEquals("adminTools.dashboard.healthcheck.security.system.lang.notFound", + langEncodingHealthCheck.check().getMessage()); + logger.warn("Language encoding could not be detected!"); + } + + @Test + void checkUnsafeEncoding() throws Exception + { + Map jsonResponse = Map.of("LANG", "en.ISO-8859-1"); + when(dataProvider.getDataAsJSON()).thenReturn(jsonResponse); + assertEquals("adminTools.dashboard.healthcheck.security.system.lang.warn", + langEncodingHealthCheck.check().getMessage()); + verify(logger).warn("[{}] encoding is [{}], but should be UTF-8!", "System language", "ISO-8859-1"); + } +} diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/job/HealthCheckJobTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/job/HealthCheckJobTest.java new file mode 100644 index 00000000..278db631 --- /dev/null +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/health/job/HealthCheckJobTest.java @@ -0,0 +1,94 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.health.job; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Provider; + +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; + +import com.xpn.xwiki.XWikiContext; +import com.xwiki.admintools.health.HealthCheck; +import com.xwiki.admintools.health.HealthCheckResult; +import com.xwiki.admintools.jobs.HealthCheckJobRequest; +import com.xwiki.admintools.jobs.HealthCheckJobStatus; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +@ComponentTest +class HealthCheckJobTest +{ + @InjectMockComponents + private HealthCheckJob healthCheckJob; + + @MockComponent + private Provider> listProvider; + + @MockComponent + private Provider wikiContextProvider; + + @MockComponent + private XWikiContext wikiContext; + + @Mock + private HealthCheck firstHealthCheck; + + @Mock + private HealthCheck secondHealthCheck; + + @Test + void createNewStatus() + { + assertEquals(HealthCheckJobStatus.class, + healthCheckJob.createNewStatus(new HealthCheckJobRequest()).getClass()); + } + + @Test + void runInternal() + { + List healthCheckList = new ArrayList<>(); + healthCheckList.add(firstHealthCheck); + healthCheckList.add(secondHealthCheck); + + when(listProvider.get()).thenReturn(healthCheckList); + when(firstHealthCheck.check()).thenReturn(new HealthCheckResult("err", "err_rec", "error")); + when(secondHealthCheck.check()).thenReturn(new HealthCheckResult("safe", "info")); + + healthCheckJob.initialize(new HealthCheckJobRequest()); + healthCheckJob.runInternal(); + HealthCheckJobStatus healthCheckJobStatus = healthCheckJob.getStatus(); + assertEquals(2, healthCheckJobStatus.getHealthCheckResults().size()); + } + + @Test + void getGroupPath() + { + when(wikiContextProvider.get()).thenReturn(wikiContext); + when(wikiContext.getWikiId()).thenReturn("xwiki"); + assertEquals(List.of("adminTools", "healthCheck", "xwiki"), healthCheckJob.getGroupPath().getPath()); + } +} diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/rest/DefaultAdminToolsResourceTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/rest/DefaultAdminToolsResourceTest.java index 87ff0e9e..d05f811a 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/rest/DefaultAdminToolsResourceTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/rest/DefaultAdminToolsResourceTest.java @@ -57,16 +57,18 @@ * @version $Id$ */ @ComponentTest -public class DefaultAdminToolsResourceTest +class DefaultAdminToolsResourceTest { - XWikiContext xWikiContext; - - @Mock - XWikiRequest xWikiRequest; + private final Map params = Map.of("noLines", new String[] { "1000" }); @InjectMockComponents private DefaultAdminToolsResource defaultAdminToolsResource; + private XWikiContext xWikiContext; + + @Mock + private XWikiRequest xWikiRequest; + @MockComponent private ImportantFilesManager importantFilesManager; @@ -85,8 +87,6 @@ public class DefaultAdminToolsResourceTest @Mock private Logger logger; - private final Map params = Map.of("noLines", new String[]{"1000"}); - @BeforeComponent void beforeComponent() { diff --git a/application-admintools-ui/pom.xml b/application-admintools-ui/pom.xml index cbb6cad9..34e5d052 100644 --- a/application-admintools-ui/pom.xml +++ b/application-admintools-ui/pom.xml @@ -96,6 +96,7 @@ .*/AdminTools/WebHome\.xml + .*/AdminTools/HelpLinks\.xml diff --git a/application-admintools-ui/src/main/resources/AdminTools/Code/AdminToolsJS.xml b/application-admintools-ui/src/main/resources/AdminTools/Code/AdminToolsJS.xml index 4447a80f..0b15bdf2 100644 --- a/application-admintools-ui/src/main/resources/AdminTools/Code/AdminToolsJS.xml +++ b/application-admintools-ui/src/main/resources/AdminTools/Code/AdminToolsJS.xml @@ -20,7 +20,7 @@ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + AdminTools.Code AdminToolsJS @@ -125,7 +125,94 @@ default - require(['jquery'], function($) { + require(['jquery', 'xwiki-meta', 'xwiki-job-runner'], function($, xwikiMeta, JobRunner) { + const getHealthCheckActionPageURL = function() { + let documentReference = XWiki.Model.resolve('AdminTools.Code.HealthCheckResources', XWiki.EntityType.DOCUMENT); + return new XWiki.Document(documentReference).getURL('get'); + }; + + const runHealthCheckJob = function() { + $('#healthCheckJobStart').prop('disabled', true); + var data = []; + data.push( + {name: 'outputSyntax', value: 'plain'}, + {name: 'sheet', value: 'wiki:AdminTools.Code.HealthCheckResources'}, + {name: 'action', value: 'healthCheck'}, + {name: 'form_token', value: xwikiMeta.form_token} + ); + return Promise.resolve(new JobRunner({ + createStatusRequest: function(jobId) { + return { + url: getHealthCheckActionPageURL(), + data: { + outputSyntax: 'plain', + sheet: 'AdminTools.Code.HealthCheckResources', + data: 'jobStatus', + jobId: jobId.join('/') + } + }; + } + }).run(getHealthCheckActionPageURL(), data)).catch((reason) => { + return Promise.reject(reason); + }).finally(() => { + $('#healthCheckJobStart').prop('disabled', false); + }); + }; + + // Need to call job.min.js only after the job has started its execution and the result message has been changed for + // the progress bar. Otherwise, job.js won't see .ui-progress and will not initialize and run a new JobRunner + // with the requested configuration. To make sure the job .ui-progress is seen, we need to undefine and request the + // resource again. + const initialiseJobJS = function() { + $.get(getHealthCheckActionPageURL(), function(data) { + let jobJSURL = $(data).find('.jobJSURL').attr('data-jobJSURL'); + require.config({ + paths: { + 'health-check-job': jobJSURL + } + }); + require(['health-check-job'], function(){}); + }); + }; + + const reinitializeJobJS = function() { + require.undef('health-check-job'); + require(['health-check-job'], function(){}); + } + + const reinitialiseHealthCheckResources = function() { + $.get(getHealthCheckActionPageURL(), function(data) { + let progressBar = $(data).find('div.ui-progress'); + $('#healthCheck').find('.successmessage, .warningmessage, .errormessage').replaceWith(progressBar); + reinitializeJobJS() + }); + }; + + $(document).ready(function() { + if ($('#healthCheck').length) { + initialiseJobJS(); + let jobState = $('.healthCheckJobState').attr('data-jobState'); + if (jobState == 'RUNNING') { + runHealthCheckJob(); + $('#healthCheck .job-status').show(); + } else if (jobState == 'FINISHED') { + $('#healthCheck .job-status').show(); + } + } + }); + + $(document).on('click', '#healthCheck .log-item-warn, #healthCheck .log-item-error', function(event) { + $(this).children('.recommendation').toggle(); + }); + + $(document).on('click', '#healthCheckJobStart', function(event) { + event.preventDefault(); + $('#healthCheck .log').empty(); + runHealthCheckJob(); + reinitialiseHealthCheckResources(); + $('#healthCheck .job-status').show(); + }); + $(document).on('click', '#downloadFilesModal .btn-primary', function(event) { event.preventDefault(); const downloadForm = $('#downloadFilesModal form'); @@ -134,10 +221,11 @@ const link = document.createElement('a'); link.href = downloadForm.attr('action') + '?' + downloadForm.serialize(); link.click(); + $(event.currentTarget).closest('.modal').modal('toggle'); }); $(document).on('click', '#filesViewLastNLinesModal .btn-primary, #configurationViewLastNLinesModal .btn-primary', - function(event) { + function(event) { event.preventDefault(); const modal = $(event.currentTarget).closest('.modal'); const downloadForm = modal.find('form'); diff --git a/application-admintools-ui/src/main/resources/AdminTools/Code/Configuration.xml b/application-admintools-ui/src/main/resources/AdminTools/Code/Configuration.xml index f67ff896..650d3a60 100644 --- a/application-admintools-ui/src/main/resources/AdminTools/Code/Configuration.xml +++ b/application-admintools-ui/src/main/resources/AdminTools/Code/Configuration.xml @@ -20,7 +20,7 @@ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + AdminTools.Code Configuration @@ -51,6 +51,24 @@ + + PureText + + 0 + PureText + + excludedLines + 2 + 1 + excludedLines + 0 + 5 + 40 + 0 + + + com.xpn.xwiki.objects.classes.TextAreaClass + 0 @@ -58,7 +76,7 @@ serverLocation 1 1 - Server location + serverLocation 30 0 @@ -66,6 +84,9 @@ com.xpn.xwiki.objects.classes.StringClass + + + diff --git a/application-admintools-ui/src/main/resources/AdminTools/Code/ConfigurationClass.xml b/application-admintools-ui/src/main/resources/AdminTools/Code/ConfigurationClass.xml index d2638bb6..6e7a9853 100644 --- a/application-admintools-ui/src/main/resources/AdminTools/Code/ConfigurationClass.xml +++ b/application-admintools-ui/src/main/resources/AdminTools/Code/ConfigurationClass.xml @@ -20,7 +20,7 @@ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + AdminTools.Code ConfigurationClass diff --git a/application-admintools-ui/src/main/resources/AdminTools/Code/HealthCheckJob.xml b/application-admintools-ui/src/main/resources/AdminTools/Code/HealthCheckJob.xml new file mode 100644 index 00000000..db45950f --- /dev/null +++ b/application-admintools-ui/src/main/resources/AdminTools/Code/HealthCheckJob.xml @@ -0,0 +1,51 @@ + + + + + + AdminTools.Code + HealthCheckJob + + + 0 + xwiki:XWiki.Admin + AdminTools.WebHome + xwiki:XWiki.Admin + xwiki:XWiki.Admin + 1.1 + HealthCheckJob + + false + xwiki/2.1 + true + {{velocity}} +#template('job_macros.vm') +#includeMacros("AdminTools.Code.HealthCheckMacros") +#set($jobId = $request.getParameterValues('jobId')) +#set($jobStatus = $services.job.getJobStatus($jobId)) +#if ($jobStatus) + #healthCheckOutputJobStatus($jobStatus) +#else + $response.setStatus(404) + #error($escapetool.xml($services.localization.render("admintools.job.notFound"))) +#end +{{/velocity}} + diff --git a/application-admintools-ui/src/main/resources/AdminTools/Code/HealthCheckMacros.xml b/application-admintools-ui/src/main/resources/AdminTools/Code/HealthCheckMacros.xml new file mode 100644 index 00000000..8c587421 --- /dev/null +++ b/application-admintools-ui/src/main/resources/AdminTools/Code/HealthCheckMacros.xml @@ -0,0 +1,175 @@ + + + + + + AdminTools.Code + HealthCheckMacros + + + 0 + xwiki:XWiki.Admin + AdminTools.WebHome + xwiki:XWiki.Admin + xwiki:XWiki.Admin + 1.1 + HealthCheckMacros + + false + xwiki/2.1 + true + {{velocity output='false'}} +#macro (getHealthCheckJobStatusJSON $status $json) + #set ($results = []) + #foreach ($result in $status.getHealthCheckResults()) + #set ($discard = $results.add({ + 'level': $result.getLevel(), + 'renderedMessage': "#printResult($result)" + })) + #end + #set ($json = $NULL) + #setVariable("$json" { + 'id': $status.request.id, + 'state': $status.state, + 'progress': { + 'offset': $status.progress.offset + }, + 'log': { + 'offset': 0, + 'items': $results + } + }) +#end + +#macro (healthCheckOutputJobStatus $jobStatus) + #getHealthCheckJobStatusJSON($jobStatus, $json, $translationPrefix) + #set ($json.message = "#healthCheckJobFinishedMessage($jobStatus)") + $response.setContentType('application/json') + $jsontool.serialize($json) +#end + +#macro (healthCheckJobFinishedMessage $status) + #if ($status.error) + #set($messageKeys = ["job.status.${status.jobType}.error", 'job.status.error']) + #set($healthCheckReportMessage = $services.localization.render($messageKeys)) + #set($messageClass = 'errormessage') + #elseif ($status.hasErrorLevel('error')) + #set($healthCheckReportMessage = $escapetool.xml($services.localization.render('adminTools.dashboard.healthcheck.message.error'))) + #set($messageClass = 'errormessage') + #elseif ($status.hasErrorLevel('warn')) + #set($healthCheckReportMessage = $escapetool.xml($services.localization.render('adminTools.dashboard.healthcheck.message.warning'))) + #set($messageClass = 'warningmessage') + #else + #set($healthCheckReportMessage = $escapetool.xml($services.localization.render('adminTools.dashboard.healthcheck.message.success'))) + #set($messageClass = 'successmessage') + #end + <div class="box $messageClass"> + $healthCheckReportMessage + </div> +#end + +#macro (printResult $healthCheckResult) + <div style="cursor: pointer;">$escapetool.xml($services.localization.render($healthCheckResult.getMessage())) + #if ($healthCheckResult.getCurrentValue()) $escapetool.xml($services.localization.render( + 'adminTools.dashboard.healthcheck.currentValue')) $healthCheckResult.getCurrentValue()#end</div> + #if($healthCheckResult.getRecommendation()) + <div class="recommendation" style="cursor: pointer;"> + $escapetool.xml($services.localization.render($healthCheckResult.getRecommendation()))</div> + #end +#end + +#macro (printHealthCheckResults $status) + #if ($status.state != 'FINISHED') + #set($loading = true) + #end + #set($healthCheckResults = $status.getHealthCheckResults()) + <ul class="log"> + #foreach ($healthCheckResult in $healthCheckResults) + #set ($resultLevel = $healthCheckResult.getLevel()) + ## Display the last result item as loading if the associated task is not finished. + <li class="log-item log-item-${resultLevel}#if ($loading && !$foreach.hasNext) log-item-loading#end"> + #printResult($healthCheckResult) + </li> + #end + </ul> +#end + +#macro (displayHealthCheckResults $status $collapsed) + <dl class="xform"> + <dt> + <label class="collapse-toggle#if ($collapsed || $status.state == 'WAITING') collapsed#end" + data-target-xpath="parent::*/following-sibling::*"> + <span class="icon-closed">$services.icon.renderHTML('caret-right')</span> + <span class="icon-opened">$services.icon.renderHTML('caret-down')</span> + $escapetool.xml($services.localization.render('adminTools.dashboard.healthcheck.result')) + </label> + </dt> + <dd>#printHealthCheckResults($status)</dd> + </dl> +#end + +#macro (healthCheckUI) + #set ($discard = $xwiki.jsx.use('AdminTools.Code.AdminToolsJS')) + #set ($jobId = $services.admintools.getHealthCheckJobId()) + #set ($healthJobStatusURL = $xwiki.getURL('AdminTools.Code.HealthCheckJob', 'get', $escapetool.url({ + 'jobId': $jobId, + 'outputSyntax': 'plain' + }))) + #set ($healthJobStatus = $services.job.getJobStatus($jobId)) + #set ($solutionLink = $xwiki.getURL('AdminTools.HelpLinks')) + #set ($description = $escapetool.xml($services.localization.render('adminTools.dashboard.healthcheck.description', [ + '__STARTLINK__', + '__ENDLINK__' + ])).replace('__STARTLINK__', "<a href='$solutionLink'><strong>").replace('__ENDLINK__', ' + </strong></a>')) + <span class="healthCheckJobState" + data-jobState="${healthJobStatus.state}"> + </span> + <div class="adminToolsDashboardItem" id="healthCheck"> + <h2>$services.icon.renderHTML('bug') + $escapetool.xml($services.localization.render('adminTools.dashboard.healthcheck.title'))</h2> + <p>$description</p> + <hr/> + <div class="healthCheckWrapper"> + <div class="healthCheckLastCheck"> + $escapetool.xml($services.localization.render('adminTools.dashboard.healthcheck.time')): + $services.date.displayTimeAgo($healthJobStatus.getEndDate()) + </div> + <div class="buttonwrapper"> + <button id="healthCheckJobStart" type="submit" class="btn btn-primary" name="startHealthCheck" + value="startHealthCheck">$escapetool.xml($services.localization.render( + 'adminTools.dashboard.healthcheck.start'))</button> + </div> + </div> + <div hidden class="xcontent job-status" data-url="${healthJobStatusURL}"> + #if ($healthJobStatus.state != 'FINISHED') + #displayJobProgressBar($healthJobStatus) + #else + #healthCheckJobFinishedMessage($healthJobStatus, $translationPrefix, $successKey, $errorKey, $canceledKey) + #end + #if ($showLogs || $isAdvancedUser || $isSuperAdmin || $isAdmin) + #displayHealthCheckResults($healthJobStatus true) + #end + </div> + </div> +#end +{{/velocity}} + diff --git a/application-admintools-ui/src/main/resources/AdminTools/Code/HealthCheckResources.xml b/application-admintools-ui/src/main/resources/AdminTools/Code/HealthCheckResources.xml new file mode 100644 index 00000000..f534d5e4 --- /dev/null +++ b/application-admintools-ui/src/main/resources/AdminTools/Code/HealthCheckResources.xml @@ -0,0 +1,85 @@ + + + + + + AdminTools.Code + HealthCheckResources + + + 0 + xwiki:XWiki.Admin + Main.WebHome + xwiki:XWiki.Admin + xwiki:XWiki.Admin + 1.1 + HealthCheckResources + + false + xwiki/2.1 + true + {{template name="job_macros.vm"/}} + +{{velocity output="false"}} +#macro (returnHealthCheckJobStatusJSON) + #set ($healthCheckJobId = $services.admintools.getHealthCheckJobId()) + #set ($healthCheckJobStatus = $services.job.getJobStatus($healthCheckJobId)) + #set ($healthCheckJobStatusJSON = { + 'id': $healthCheckJobStatus.request.id, + 'state': $healthCheckJobStatus.state, + 'progress': { + 'offset': $healthCheckJobStatus.progress.offset + } + }) + #jsonResponse($healthCheckJobStatusJSON) +#end + +#macro (getHealthCheckJobResources) + #set ($jobJSURL = $xwiki.getSkinFile('uicomponents/job/job.js')) + #set ($jobId = $services.admintools.getHealthCheckJobId()) + #set ($healthJobStatus = $services.job.getJobStatus($jobId)) + {{html clean=false}} + <div> + <span class="jobJSURL" + data-jobJSURL="${jobJSURL}"> + </span> + #displayJobProgressBar($healthJobStatus) + </div> + {{/html}} +#end +{{/velocity}} + +{{velocity}} +#if ($xcontext.action == 'get') + #if ("$!request.action" != '' && !$services.csrf.isTokenValid($request.form_token)) + #set ($discard = $response.sendError(401, 'CSRF token verification failed!')) + #elseif ($request.action == 'healthCheck') + #set ($healthCheckJob = $services.admintools.runHealthChecks()) + #returnHealthCheckJobStatusJSON() + #elseif ($request.data == 'jobStatus') + #set ($healthCheckJobId = $request.jobId.split('/')) + #returnHealthCheckJobStatusJSON($healthCheckJobId) + #else + #getHealthCheckJobResources() + #end +#end +{{/velocity}} + diff --git a/application-admintools-ui/src/main/resources/AdminTools/Code/Macros.xml b/application-admintools-ui/src/main/resources/AdminTools/Code/Macros.xml index f06a51af..0be60386 100644 --- a/application-admintools-ui/src/main/resources/AdminTools/Code/Macros.xml +++ b/application-admintools-ui/src/main/resources/AdminTools/Code/Macros.xml @@ -20,7 +20,7 @@ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + AdminTools.Code Macros diff --git a/application-admintools-ui/src/main/resources/AdminTools/Code/Translations.xml b/application-admintools-ui/src/main/resources/AdminTools/Code/Translations.xml index 3a4f7687..b0137b19 100644 --- a/application-admintools-ui/src/main/resources/AdminTools/Code/Translations.xml +++ b/application-admintools-ui/src/main/resources/AdminTools/Code/Translations.xml @@ -20,7 +20,7 @@ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + AdminTools.Code Translations @@ -44,59 +44,137 @@ AdminTools.Code.ConfigurationClass_serverLocation.hint=Path to the server locati admin.admintools.description=Configure Admin Tools Application adminTools.extension.name=Admin Tools Application (Pro) +## Dashboard sections +## Config +adminTools.dashboard.backend.configuration.error=Server path was not found. Please manually add the path to the server on the Admin Tools configuration page. +adminTools.dashboard.backend.description=Get info about your backend +adminTools.dashboard.backend.java=Detected java version +adminTools.dashboard.backend.os.architecture=OS architecture +adminTools.dashboard.backend.os.legend=OS info +adminTools.dashboard.backend.os.name=OS name +adminTools.dashboard.backend.os.version=OS version +adminTools.dashboard.backend.supportedDB.error=Database not found. Currently supported databases +adminTools.dashboard.backend.supportedServers.error=Currently supported servers +adminTools.dashboard.backend.title=Backend +adminTools.dashboard.backend.usedDB=Used database +adminTools.dashboard.backend.usedServer=Used server +adminTools.dashboard.backend.xwiki.version=XWiki installation version + +## Files +adminTools.dashboard.download.description=Get the files you need. View them directly in the browser or download them as an archive. +adminTools.dashboard.download.label=Export files needed for getting support +adminTools.dashboard.download.title=Files +adminTools.dashboard.download.view.configuration=XWiki configuration file +adminTools.dashboard.download.view.description=View files content +adminTools.dashboard.download.view.properties=XWiki properties file +adminTools.dashboard.download.warning=Before downloading and sending the files, please make sure you introduced the lines that may contain sensitive info in Admin Tools configuration page! + +## Health check +adminTools.dashboard.healthcheck.database.info=Database status OK. +adminTools.dashboard.healthcheck.database.warn=Database not found! +adminTools.dashboard.healthcheck.database.notSupported=Used database is not supported! +adminTools.dashboard.healthcheck.database.recommendation=The used database is currently not supported by XWiki. Check the help links to find the database compatibility requirements. +adminTools.dashboard.healthcheck.description=Check if your instance is configured correctly and is properly running. For any issues, check out this {0}help links{1}. +adminTools.dashboard.healthcheck.java.info=Java status OK. +adminTools.dashboard.healthcheck.java.warn=Java version not found! +adminTools.dashboard.healthcheck.java.warn.recommendation=Java version could not be found! Please make sure you correctly installed and configured the paths for your Java installation. For further help, consult the help links. +adminTools.dashboard.healthcheck.java.error=Java version is not compatible with the current XWiki installation! +adminTools.dashboard.healthcheck.java.error.recommendation=The current version of Java that you are using it is not compatible with the XWiki installation version. Please check the help links to view the compatibility. +adminTools.dashboard.healthcheck.memory.cache.info=Document cache status OK. +adminTools.dashboard.healthcheck.memory.cache.null=Document cache capacity currently set at 500. +adminTools.dashboard.healthcheck.memory.cache.null.recommendation=Document store cache capacity was not confiugred and is set by default to 500. See cache recommendations in help links above. +adminTools.dashboard.healthcheck.memory.cache.low=Document cache capacity is set to a low value. See cache recommendations in the help links page. +adminTools.dashboard.healthcheck.memory.free.error=Your JVM instance has less than 512MB of free memory left. +adminTools.dashboard.healthcheck.memory.free.warn=Your instance memory is running low. +adminTools.dashboard.healthcheck.memory.info=Memory status OK. +adminTools.dashboard.healthcheck.memory.maxcapacity.error=JVM memory is less than 1024MB. +adminTools.dashboard.healthcheck.memory.recommendation=Allocate more resources to you JVM! Check the help links for further help. +adminTools.dashboard.healthcheck.os.info=OS info retrieval OK. +adminTools.dashboard.healthcheck.os.warn=There has been an error while gathering OS info! +adminTools.dashboard.healthcheck.performance.cpu.warn=The CPU does not satisfy the minimum system requirements! +adminTools.dashboard.healthcheck.performance.cpu.recommendation=The CPU should have a minimum of 2 Cores, 2800MHz frequency and 2048KB cache size. View the help page for more details. +adminTools.dashboard.healthcheck.performance.cpu.info=CPU performance OK. +adminTools.dashboard.healthcheck.performance.info=System performance OK. +adminTools.dashboard.healthcheck.performance.memory.warn=There is not enough memory to safely run the XWiki installation! +adminTools.dashboard.healthcheck.performance.memory.info=System memory capacity OK. +adminTools.dashboard.healthcheck.performance.memory.recommendation=It is recommended to have at least 2GB of RAM to run XWiki. +adminTools.dashboard.healthcheck.performance.space.warn=There is not enough free space for the XWiki installation! +adminTools.dashboard.healthcheck.performance.space.recommendation=There should be at least 16GB of free system space. +adminTools.dashboard.healthcheck.performance.space.info=The system has enough free space for the XWiki installation. +adminTools.dashboard.healthcheck.security.system.info=System encoding OK. +adminTools.dashboard.healthcheck.security.system.file.warn=System file encoding is NOT UTF-8! +adminTools.dashboard.healthcheck.security.system.file.info=System file encoding is set to UTF-8. +adminTools.dashboard.healthcheck.security.system.file.notFound=File encoding could not be detected! +adminTools.dashboard.healthcheck.security.system.lang.warn=System language encoding is NOT UTF-8! +adminTools.dashboard.healthcheck.security.system.lang.info=System language encoding is set to UTF-8. +adminTools.dashboard.healthcheck.security.system.lang.notFound=Language encoding could not be detected! +adminTools.dashboard.healthcheck.security.system.recommendation=System encoding should be set to UTF-8! Please consult the help links page to get further instructions of how to configure the system encoding. +adminTools.dashboard.healthcheck.security.xwiki.info=XWiki encoding OK. +adminTools.dashboard.healthcheck.security.xwiki.active.warn=XWiki active encoding is NOT UTF-8! +adminTools.dashboard.healthcheck.security.xwiki.active.info=XWiki active encoding is set to UTF-8. +adminTools.dashboard.healthcheck.security.xwiki.active.notFound=Active encoding could not be detected! +adminTools.dashboard.healthcheck.security.xwiki.config.warn=XWiki configuration encoding is NOT UTF-8! +adminTools.dashboard.healthcheck.security.xwiki.config.info=XWiki configuration encoding is set to UTF-8. +adminTools.dashboard.healthcheck.security.xwiki.config.notFound=Configuration encoding could not be detected! +adminTools.dashboard.healthcheck.title=Health check +adminTools.dashboard.healthcheck.time=Time since the last health check +adminTools.dashboard.healthcheck.start=Start health check +adminTools.dashboard.healthcheck.currentValue=Current value: +adminTools.job.notFound=Health check job status not found +adminTools.dashboard.healthcheck.message.success=No issue found! +adminTools.dashboard.healthcheck.message.warning=Some issues have been found, for more details please see the results below. +adminTools.dashboard.healthcheck.message.error=Critical issues were found, please consult the results below! +adminTools.dashboard.healthcheck.result=Health check results + +## Security +adminTools.dashboard.security.activeEncoding=Active encoding +adminTools.dashboard.security.configurationEncoding=Configuration encoding +adminTools.dashboard.security.description=See an overview of your security information. +adminTools.dashboard.security.error=Error while gathering security information. +adminTools.dashboard.security.fileEncoding=File encoding +adminTools.dashboard.security.lang=Used language +adminTools.dashboard.security.pwd=Working directory +adminTools.dashboard.security.title=Security + + +##Help links +adminTools.helpPage.browser.support=Browser support +adminTools.helpPage.browser.title=Browser +adminTools.helpPage.database.instructions=Specific databases instructions +adminTools.helpPage.database.mysql.install=MySQL installation guide +adminTools.helpPage.database.mysql.troubleshoot=MySQL troubleshoot +adminTools.helpPage.database.supported=Supported databases +adminTools.helpPage.database.title=Database issues +adminTools.helpPage.java.memory=Java memory +adminTools.helpPage.java.support=Java support +adminTools.helpPage.java.title=Java +adminTools.helpPage.other.title=Other issues +adminTools.helpPage.performance.cache=Cache recommendations +adminTools.helpPage.performance.hardware=Hardware requirements +adminTools.helpPage.performance.memory=Memory recommendations +adminTools.helpPage.performance.title=Performance issues +adminTools.helpPage.server.security=Security configuration +adminTools.helpPage.server.supported=Supported servers +adminTools.helpPage.server.title=Server issues +adminTools.helpPage.server.tomcat=Tomcat recommendations + + ## Modals adminTools.dashboard.download.modal.button=Download adminTools.dashboard.download.modal.date.from=From adminTools.dashboard.download.modal.date.to=To +adminTools.dashboard.download.modal.logs.filter.placeholder.from=Logs from date... +adminTools.dashboard.download.modal.logs.filter.placeholder.to=Logs to date... +adminTools.dashboard.download.modal.logs.title=Logs adminTools.dashboard.download.modal.provided=Configuration info adminTools.dashboard.download.modal.title=Get support files adminTools.dashboard.download.modal.xwikiConfig.title=xwiki.cfg adminTools.dashboard.download.modal.xwikiProperties.title=xwiki.properties -adminTools.dashboard.download.modal.logs.title=Logs -adminTools.dashboard.download.modal.logs.filter.placeholder.from=Logs from date... -adminTools.dashboard.download.modal.logs.filter.placeholder.to=Logs to date... -adminTools.dashboard.logs.modal.submit=View +adminTools.dashboard.logs.modal.nLines.hint=The maximum number of lines is 50000, since the complete logs can also be downloaded. If no value is defined, 1000 will be used as a default value. adminTools.dashboard.logs.modal.nLines.label=Number of extracted lines +adminTools.dashboard.logs.modal.submit=View adminTools.dashboard.logs.modal.title=Show last n lines of log -adminTools.dashboard.logs.modal.nLines.hint=The maximum number of lines is 50000, since the complete logs can also be downloaded. If no value is defined, 1000 will be used as a default value. -adminTools.dashboard.showLogs=View last n lines of log... - -## Dashboard sections -## Config -adminTools.dashboard.section.backend.configuration.error=Server path was not found. Please manually add the path to the server on the Admin Tools configuration page. -adminTools.dashboard.section.backend.description=Get info about your backend -adminTools.dashboard.section.backend.java=Detected java version -adminTools.dashboard.section.backend.os.architecture=OS architecture -adminTools.dashboard.section.backend.os.legend=OS info -adminTools.dashboard.section.backend.os.name=OS name -adminTools.dashboard.section.backend.os.version=OS version -adminTools.dashboard.section.backend.supportedDB.error=Database not found. Currently supported databases -adminTools.dashboard.section.backend.supportedServers.error=Currently supported servers -adminTools.dashboard.section.backend.title=Backend -adminTools.dashboard.section.backend.usedDB=Used database -adminTools.dashboard.section.backend.usedServer=Used server -adminTools.dashboard.section.backend.xwiki.version=XWiki installation version - -## Files -adminTools.dashboard.section.download.description=Get the files you need. View them directly in the browser or download them as an archive. -adminTools.dashboard.section.download.label=Export files needed for getting support -adminTools.dashboard.section.download.title=Files -adminTools.dashboard.section.download.view.configuration=XWiki configuration file -adminTools.dashboard.section.download.view.description=View files content -adminTools.dashboard.section.download.view.properties=XWiki properties file -adminTools.dashboard.section.download.warning=Before downloading and sending the files, please make sure you introduced the lines that may contain sensitive info in Admin Tools configuration page! - -## Security -adminTools.dashboard.section.security.activeEncoding=Active encoding -adminTools.dashboard.section.security.configurationEncoding=Configuration encoding -adminTools.dashboard.section.security.description=See an overview of your security information. -adminTools.dashboard.section.security.error=Error while gathering security information. -adminTools.dashboard.section.security.fileEncoding=File encoding -adminTools.dashboard.section.security.lang=Used language -adminTools.dashboard.section.security.pwd=Working directory -adminTools.dashboard.section.security.title=Security - - +adminTools.dashboard.showLogs=View last n lines of log... AdminTools.Code.Translations 0 @@ -122,8 +200,8 @@ adminTools.dashboard.section.security.title=Security 1 Scope 0 - - |, + + |, 1 0 GLOBAL|WIKI|USER|ON_DEMAND diff --git a/application-admintools-ui/src/main/resources/AdminTools/HelpLinks.xml b/application-admintools-ui/src/main/resources/AdminTools/HelpLinks.xml new file mode 100644 index 00000000..d6a80179 --- /dev/null +++ b/application-admintools-ui/src/main/resources/AdminTools/HelpLinks.xml @@ -0,0 +1,95 @@ + + + + + + AdminTools + HelpLinks + + en + 0 + xwiki:XWiki.Admin + AdminTools.WebHome + xwiki:XWiki.Admin + xwiki:XWiki.Admin + 1.1 + Help links + + false + xwiki/2.1 + false + {{box cssClass="floatinginfobox" title="**Contents**"}} +{{toc/}} +{{/box}} + +{{velocity}} += {{translation key="adminTools.helpPage.performance.title" /}} = + +* [[{{translation key="adminTools.helpPage.performance.hardware" /}} +>>https://www.xwiki.org/xwiki/bin/view/Documentation/AdminGuide/Performances/#HSizing||target="_blank"]] +* [[{{translation key="adminTools.helpPage.performance.memory" /}} +>>https://www.xwiki.org/xwiki/bin/view/Documentation/AdminGuide/Performances/#HMemory||target="_blank"]] +* [[{{translation key="adminTools.helpPage.performance.cache" /}} +>>https://www.xwiki.org/xwiki/bin/view/Documentation/AdminGuide/Performances/#HDocumentCache +||target="_blank"]] + += {{translation key="adminTools.helpPage.server.title" /}} = + +* [[{{translation key="adminTools.helpPage.server.security" /}} +>>https://www.xwiki.org/xwiki/bin/view/Documentation/AdminGuide/Configuration/Encoding/ +||target="_blank"]] +* [[{{translation key="adminTools.helpPage.server.supported" /}} +>>https://dev.xwiki.org/xwiki/bin/view/Community/SupportStrategy/ServletContainerSupportStrategy/ +||target="_blank"]] +* [[{{translation key="adminTools.helpPage.server.tomcat" /}} +>>https://www.xwiki.org/xwiki/bin/view/Documentation/AdminGuide/Installation/InstallationWAR/InstallationTomcat/#HRecommendations +||target="_blank"]] + += {{translation key="adminTools.helpPage.database.title" /}} = + +* [[{{translation key="adminTools.helpPage.database.supported" /}} +>>https://dev.xwiki.org/xwiki/bin/view/Community/SupportStrategy/DatabaseSupportStrategy||target="_blank"]] +* [[{{translation key="adminTools.helpPage.database.instructions" /}} +>>https://www.xwiki.org/xwiki/bin/view/Documentation/AdminGuide/Installation/InstallationWAR/#HSpecificdatabasesinstructions +||target="_blank"]] +* [[{{translation key="adminTools.helpPage.database.mysql.install" /}} +>>https://www.xwiki.org/xwiki/bin/view/Documentation/AdminGuide/Installation/InstallationWAR/InstallationMySQL/#HInstallationSteps +||target="_blank"]] +* [[{{translation key="adminTools.helpPage.database.mysql.troubleshoot" /}} +>>https://www.xwiki.org/xwiki/bin/view/Documentation/AdminGuide/Installation/InstallationWAR/InstallationMySQL/#HTroubleshooting +||target="_blank"]] + += {{translation key="adminTools.helpPage.other.title" /}} = +== {{translation key="adminTools.helpPage.java.title" /}} == + +* [[{{translation key="adminTools.helpPage.java.memory" /}} +>>https://www.xwiki.org/xwiki/bin/view/Documentation/AdminGuide/Installation/InstallationWAR/InstallationTomcat/#HGeneralMemorySettings +||target="_blank"]] +* [[{{translation key="adminTools.helpPage.java.support" /}} +>>https://dev.xwiki.org/xwiki/bin/view/Community/SupportStrategy/JavaSupportStrategy/||target="_blank"]] + +== {{translation key="adminTools.helpPage.browser.title" /}} == + +* [[{{translation key="adminTools.helpPage.browser.support" /}} +>>https://dev.xwiki.org/xwiki/bin/view/Community/SupportStrategy/BrowserSupportStrategy||target="_blank"]] +{{/velocity}} + + diff --git a/application-admintools-ui/src/main/resources/AdminTools/WebHome.xml b/application-admintools-ui/src/main/resources/AdminTools/WebHome.xml index 1bf52acc..b33f02e8 100644 --- a/application-admintools-ui/src/main/resources/AdminTools/WebHome.xml +++ b/application-admintools-ui/src/main/resources/AdminTools/WebHome.xml @@ -20,7 +20,7 @@ * 02110-1301 USA, or see the FSF site: http://www.fsf.org. --> - + AdminTools WebHome @@ -182,6 +182,76 @@ </property> </object> + <object> + <name>AdminTools.WebHome</name> + <number>3</number> + <className>XWiki.GadgetClass</className> + <guid>7ac72ccf-e4d2-474f-b279-ae650ac57a58</guid> + <class> + <name>XWiki.GadgetClass</name> + <customClass/> + <customMapping/> + <defaultViewSheet/> + <defaultEditSheet/> + <defaultWeb/> + <nameField/> + <validationScript/> + <content> + <disabled>0</disabled> + <editor>---</editor> + <name>content</name> + <number>2</number> + <picker>0</picker> + <prettyName>content</prettyName> + <rows>5</rows> + <size>40</size> + <unmodifiable>0</unmodifiable> + <validationMessage/> + <validationRegExp/> + <classType>com.xpn.xwiki.objects.classes.TextAreaClass</classType> + </content> + <position> + <disabled>0</disabled> + <name>position</name> + <number>3</number> + <picker>0</picker> + <prettyName>position</prettyName> + <size>30</size> + <unmodifiable>0</unmodifiable> + <validationMessage/> + <validationRegExp/> + <classType>com.xpn.xwiki.objects.classes.StringClass</classType> + </position> + <title> + <disabled>0</disabled> + <name>title</name> + <number>1</number> + <picker>0</picker> + <prettyName>title</prettyName> + <size>30</size> + <unmodifiable>0</unmodifiable> + <validationMessage/> + <validationRegExp/> + <classType>com.xpn.xwiki.objects.classes.StringClass</classType> + + + + {{template name="job_macros.vm"/}} + +{{velocity}} + #includeMacros("AdminTools.Code.HealthCheckMacros") + {{html clean='false'}} + #healthCheckUI() + {{/html}} +{{/velocity}} + + + 1, 2 + + + + </property> + </object> <object> <name>AdminTools.WebHome</name> <number>0</number> @@ -309,8 +379,19 @@ margin: 2rem 4rem; } +/* Make sure the date picker is always on top */ .bootstrap-datetimepicker-widget { z-index: 99999 !important; +} + +.healthCheckWrapper { + display: flex; + flex-direction: column; + margin-bottom: 2rem; +} + +.healthCheckWrapper button { + margin-top: 2rem; }</code> </property> <property>