diff --git a/Plan/bukkit/src/main/java/com/djrapitops/plan/commands/use/BukkitCommand.java b/Plan/bukkit/src/main/java/com/djrapitops/plan/commands/use/BukkitCommand.java index 33471fd11..51ce1bffd 100644 --- a/Plan/bukkit/src/main/java/com/djrapitops/plan/commands/use/BukkitCommand.java +++ b/Plan/bukkit/src/main/java/com/djrapitops/plan/commands/use/BukkitCommand.java @@ -37,7 +37,11 @@ public class BukkitCommand implements CommandExecutor, TabCompleter { private final ErrorLogger errorLogger; private final Subcommand command; - public BukkitCommand(RunnableFactory runnableFactory, ErrorLogger errorLogger, Subcommand command) { + public BukkitCommand( + RunnableFactory runnableFactory, + ErrorLogger errorLogger, + Subcommand command + ) { this.runnableFactory = runnableFactory; this.errorLogger = errorLogger; this.command = command; diff --git a/Plan/bungeecord/src/main/java/com/djrapitops/plan/command/use/BungeeCommand.java b/Plan/bungeecord/src/main/java/com/djrapitops/plan/command/use/BungeeCommand.java index c79f2289e..98aab509f 100644 --- a/Plan/bungeecord/src/main/java/com/djrapitops/plan/command/use/BungeeCommand.java +++ b/Plan/bungeecord/src/main/java/com/djrapitops/plan/command/use/BungeeCommand.java @@ -41,8 +41,8 @@ public class BungeeCommand extends Command implements TabExecutor { public BungeeCommand( RunnableFactory runnableFactory, - ErrorLogger errorLogger, Subcommand command, - String name + ErrorLogger errorLogger, + Subcommand command, String name ) { super(name); this.runnableFactory = runnableFactory; diff --git a/Plan/common/src/main/java/com/djrapitops/plan/PlanSystem.java b/Plan/common/src/main/java/com/djrapitops/plan/PlanSystem.java index 0bac77e75..d001a47b1 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/PlanSystem.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/PlanSystem.java @@ -293,6 +293,13 @@ public class PlanSystem implements SubSystem { return extensionService; } + /** + * Originally visible for testing purposes. + * + * @return the error logger of the system + * @deprecated A smell, dagger should be used to construct things instead. + */ + @Deprecated public ErrorLogger getErrorLogger() { return errorLogger; } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/modules/SystemObjectProvidingModule.java b/Plan/common/src/main/java/com/djrapitops/plan/modules/SystemObjectProvidingModule.java index 7339df785..af4c80db0 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/modules/SystemObjectProvidingModule.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/modules/SystemObjectProvidingModule.java @@ -22,6 +22,8 @@ import com.djrapitops.plan.settings.config.PlanConfig; import com.djrapitops.plan.settings.locale.Locale; import com.djrapitops.plan.settings.locale.LocaleSystem; import com.djrapitops.plan.storage.file.JarResource; +import com.djrapitops.plan.utilities.logging.ErrorLogger; +import com.djrapitops.plan.utilities.logging.PluginErrorLogger; import dagger.Module; import dagger.Provides; @@ -70,4 +72,10 @@ public class SystemObjectProvidingModule { return plugin.getDataFolder(); } + @Provides + @Singleton + ErrorLogger provideErrorLogger(PluginErrorLogger errorLogger) { + return errorLogger; + } + } \ No newline at end of file diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/logging/ErrorContext.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/logging/ErrorContext.java index e4cedb6a1..b0f96fa86 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/utilities/logging/ErrorContext.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/logging/ErrorContext.java @@ -81,4 +81,12 @@ public class ErrorContext implements Serializable { return context; } } + + @Override + public String toString() { + return "ErrorContext{" + + "related=" + related + + ", whatToDo='" + whatToDo + '\'' + + '}'; + } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/logging/ErrorLogger.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/logging/ErrorLogger.java index cd007033a..c0744a1e9 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/utilities/logging/ErrorLogger.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/logging/ErrorLogger.java @@ -16,284 +16,22 @@ */ package com.djrapitops.plan.utilities.logging; -import com.djrapitops.plan.PlanPlugin; -import com.djrapitops.plan.delivery.formatting.Formatters; import com.djrapitops.plan.exceptions.ExceptionWithContext; -import com.djrapitops.plan.identification.properties.ServerProperties; -import com.djrapitops.plan.storage.file.PlanFiles; -import com.djrapitops.plan.utilities.java.Lists; -import com.djrapitops.plan.version.VersionChecker; import com.djrapitops.plugin.logging.L; -import com.djrapitops.plugin.logging.console.PluginLogger; import com.djrapitops.plugin.logging.error.ErrorHandler; -import dagger.Lazy; -import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.lang3.StringUtils; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * New logger that logs errors to specific files. - * - * @author Rsl1122 - */ -@Singleton -public class ErrorLogger implements ErrorHandler { - - private final PlanPlugin plugin; - private final PluginLogger logger; - private final PlanFiles files; - private final Lazy serverProperties; - private final Lazy versionChecker; - private final Lazy formatters; - - @Inject - public ErrorLogger( - PlanPlugin plugin, - PluginLogger logger, - PlanFiles files, - Lazy serverProperties, - Lazy versionChecker, - Lazy formatters - ) { - this.plugin = plugin; - this.logger = logger; - this.files = files; - this.serverProperties = serverProperties; - this.versionChecker = versionChecker; - this.formatters = formatters; - } - - public void log(L level, T throwable) { +public interface ErrorLogger extends ErrorHandler { + default void log(L level, T throwable) { log(level, (Throwable) throwable, throwable.getContext().orElse(ErrorContext.builder().related("Missing Context").build())); } - public void log(L level, Throwable throwable, ErrorContext context) { - String errorName = throwable.getClass().getSimpleName(); - String hash = hash(throwable); - Path logsDir = files.getLogsDirectory(); - Path errorLog = logsDir.resolve(errorName + "-" + hash + ".txt"); - mergeAdditionalContext(throwable, context); - if (Files.exists(errorLog)) { - logExisting(errorLog, throwable, context, hash); - } else { - logNew(errorLog, throwable, context, hash); - } - logToConsole(level, errorLog, throwable, context); - if (L.CRITICAL == level) { - plugin.getPluginLogger().error("CRITICAL error triggered a plugin shutdown."); - plugin.onDisable(); - } - } - - public void mergeAdditionalContext(Throwable throwable, ErrorContext context) { - Throwable cause = throwable.getCause(); - while (cause != null) { - if (cause instanceof ExceptionWithContext) { - ((ExceptionWithContext) cause).getContext().ifPresent(context::merge); - } - cause = cause.getCause(); - } - } - - private void logExisting(Path errorLog, Throwable throwable, ErrorContext context, String hash) { - // Read existing - List lines; - try (Stream read = Files.lines(errorLog)) { - lines = read.collect(Collectors.toList()); - } catch (IOException e) { - logAfterReadError(errorLog, throwable, context, hash); - return; - } - int occurrences = getOccurrences(lines) + 1; - List newLines = buildNewLines(context, lines, occurrences, hash); - overwrite(errorLog, throwable, newLines); - } - - private void overwrite(Path errorLog, Throwable throwable, List newLines) { - try { - Files.write(errorLog, newLines, StandardOpenOption.TRUNCATE_EXISTING); - } catch (IOException e) { - throwable.addSuppressed(e); - Logger.getGlobal().log(Level.SEVERE, "Failed to log Plan error, see suppressed.", throwable); - } - } - - private List buildNewLines(ErrorContext context, List lines, int occurrences, String hash) { - Lists.Builder builder = Lists.builder(String.class) - .add(hash + " - Last occurred: " + getTimeStamp() + " Occurrences: " + occurrences); - // 5 contexts are enough. - if (occurrences <= 5) { - builder = buildContext(context, occurrences, builder); - } - int lineCount = lines.size(); - int firstContextLineIndex = findFirstContextLine(lines, lineCount); - return builder.addAll(lines.subList(firstContextLineIndex, lineCount)) - .build(); - } - - private String getTimeStamp() { - return formatters.get().iso8601NoClockLong().apply(System.currentTimeMillis()); - } - - private Lists.Builder buildContext(ErrorContext context, int occurrences, Lists.Builder builder) { - return builder.add("---- Context " + occurrences + " ----") - .add("Plan v" + versionChecker.get().getCurrentVersion()) - .add(serverProperties.get().getName() + " " + serverProperties.get().getVersion()) - .add("Server v" + serverProperties.get().getImplVersion()) - .add("") - .addAll(context.toLines()) - .add(""); - } - - private void logAfterReadError(Path errorLog, Throwable throwable, ErrorContext context, String hash) { - logger.error("Failed to read " + errorLog + " deleting file"); - try { - Files.deleteIfExists(errorLog); - } catch (IOException ioException) { - logger.error("Failed to delete " + errorLog); - } - logNew(errorLog, throwable, context, hash); - } - - private int getOccurrences(List lines) { - String occurLine = lines.get(0); - return Integer.parseInt(StringUtils.splitByWholeSeparator(occurLine, ": ")[2].trim()); - } - - private int findFirstContextLine(List lines, int lineCount) { - int firstContextLineIndex = 0; - for (int i = 0; i < lineCount; i++) { - if (lines.get(i).contains("---- Context")) { - firstContextLineIndex = i; - break; - } - } - return firstContextLineIndex; - } - - private void logToConsole(L level, Path errorLog, Throwable throwable, ErrorContext context) { - String errorName = throwable.getClass().getSimpleName(); - String errorMsg = throwable.getMessage(); - String errorLocation = errorLog.toString(); - logger.log(level, - "Ran into " + errorName + " - logged to " + errorLocation, - "(INCLUDE CONTENTS OF THE FILE IN ANY REPORTS)", - context.getWhatToDo().map(td -> "What to do: " + td).orElse("Error msg: \"" + errorMsg + "\"") - ); - } - - private void logNew(Path errorLog, Throwable throwable, ErrorContext context, String hash) { - List stacktrace = buildReadableStacktrace(new ArrayList<>(), throwable); - List lines = Lists.builder(String.class) - .add(hash + " - Last occurred: " + getTimeStamp() + " Occurrences: 1") - .apply(builder -> this.buildContext(context, 1, builder)) - .add("---- Stacktrace ----") - .addAll(stacktrace) - .build(); - writeNew(errorLog, throwable, lines); - } - - private void writeNew(Path errorLog, Throwable throwable, List lines) { - try { - Files.createDirectories(errorLog.getParent()); - Files.write(errorLog, lines, StandardOpenOption.CREATE_NEW, StandardOpenOption.APPEND); - } catch (IOException e) { - throwable.addSuppressed(e); - Logger.getGlobal().log(Level.SEVERE, "Failed to log Plan error, see suppressed.", throwable); - } - } + void log(L level, Throwable throwable, ErrorContext context); @Override @Deprecated - public void log(L level, Class caughtBy, Throwable throwable) { + default void log(L level, Class caughtBy, Throwable throwable) { log(level, throwable, ErrorContext.builder() .related("Caught by " + caughtBy.getName()) .build()); } - - private String hash(Throwable e) { - int seed = 0; - Throwable cause = e; - String previousLine = null; - while (cause != null) { - for (StackTraceElement element : cause.getStackTrace()) { - String asLine = element.toString(); - if (asLine.equals(previousLine)) continue; - if (seed == 0) { - seed = asLine.hashCode(); - } else { - seed *= asLine.hashCode(); - } - previousLine = asLine; - } - cause = cause.getCause(); - } - return DigestUtils.sha256Hex(Integer.toString(seed)).substring(0, 10); - } - - private List buildReadableStacktrace(List trace, Throwable e) { - trace.add(e.toString()); - Deduplicator deduplicator = new Deduplicator(); - for (StackTraceElement element : e.getStackTrace()) { - String line = element.toString(); - deduplicator.addLines(trace, line); - } - deduplicator.addLeftoverDuplicateCountLine(trace); - Throwable[] suppressed = e.getSuppressed(); - if (suppressed.length > 0) { - for (Throwable suppressedThrowable : suppressed) { - trace.add(" Suppressed:"); - for (String line : buildReadableStacktrace(new ArrayList<>(), suppressedThrowable)) { - trace.add(" " + line); - } - } - } - Throwable cause = e.getCause(); - if (cause != null) { - trace.add("Caused by:"); - buildReadableStacktrace(trace, cause); - } - return trace; - } - - private static class Deduplicator { - private String previousLine = null; - private String lastDuplicate = null; - private int duplicateCount = 0; - - public void addLines(List trace, String line) { - if (duplicateCount > 0 && !line.equals(lastDuplicate)) { - String returnLine = " x " + duplicateCount; - duplicateCount = 1; - trace.add(returnLine); - trace.add(" " + line); - } else if (line.equals(lastDuplicate)) { - duplicateCount++; - } else if (line.equals(previousLine)) { - lastDuplicate = line; - duplicateCount = 2; - } else { - previousLine = line; - trace.add(" " + line); - } - } - - public void addLeftoverDuplicateCountLine(List trace) { - if (duplicateCount > 0) { - trace.add(" x " + duplicateCount); - } - } - } } diff --git a/Plan/common/src/main/java/com/djrapitops/plan/utilities/logging/PluginErrorLogger.java b/Plan/common/src/main/java/com/djrapitops/plan/utilities/logging/PluginErrorLogger.java new file mode 100644 index 000000000..69210a613 --- /dev/null +++ b/Plan/common/src/main/java/com/djrapitops/plan/utilities/logging/PluginErrorLogger.java @@ -0,0 +1,287 @@ +/* + * This file is part of Player Analytics (Plan). + * + * Plan is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License v3 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Plan 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 Plan. If not, see . + */ +package com.djrapitops.plan.utilities.logging; + +import com.djrapitops.plan.PlanPlugin; +import com.djrapitops.plan.delivery.formatting.Formatters; +import com.djrapitops.plan.exceptions.ExceptionWithContext; +import com.djrapitops.plan.identification.properties.ServerProperties; +import com.djrapitops.plan.storage.file.PlanFiles; +import com.djrapitops.plan.utilities.java.Lists; +import com.djrapitops.plan.version.VersionChecker; +import com.djrapitops.plugin.logging.L; +import com.djrapitops.plugin.logging.console.PluginLogger; +import dagger.Lazy; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * New logger that logs errors to specific files. + * + * @author Rsl1122 + */ +@Singleton +public class PluginErrorLogger implements ErrorLogger { + + private final PlanPlugin plugin; + private final PluginLogger logger; + private final PlanFiles files; + private final Lazy serverProperties; + private final Lazy versionChecker; + private final Lazy formatters; + + @Inject + public PluginErrorLogger( + PlanPlugin plugin, + PluginLogger logger, + PlanFiles files, + Lazy serverProperties, + Lazy versionChecker, + Lazy formatters + ) { + this.plugin = plugin; + this.logger = logger; + this.files = files; + this.serverProperties = serverProperties; + this.versionChecker = versionChecker; + this.formatters = formatters; + } + + @Override + public void log(L level, Throwable throwable, ErrorContext context) { + String errorName = throwable.getClass().getSimpleName(); + String hash = hash(throwable); + Path logsDir = files.getLogsDirectory(); + Path errorLog = logsDir.resolve(errorName + "-" + hash + ".txt"); + mergeAdditionalContext(throwable, context); + if (Files.exists(errorLog)) { + logExisting(errorLog, throwable, context, hash); + } else { + logNew(errorLog, throwable, context, hash); + } + logToConsole(level, errorLog, throwable, context); + if (L.CRITICAL == level) { + plugin.getPluginLogger().error("CRITICAL error triggered a plugin shutdown."); + plugin.onDisable(); + } + } + + private void mergeAdditionalContext(Throwable throwable, ErrorContext context) { + Throwable cause = throwable.getCause(); + while (cause != null) { + if (cause instanceof ExceptionWithContext) { + ((ExceptionWithContext) cause).getContext().ifPresent(context::merge); + } + cause = cause.getCause(); + } + } + + private void logExisting(Path errorLog, Throwable throwable, ErrorContext context, String hash) { + // Read existing + List lines; + try (Stream read = Files.lines(errorLog)) { + lines = read.collect(Collectors.toList()); + } catch (IOException e) { + logAfterReadError(errorLog, throwable, context, hash); + return; + } + int occurrences = getOccurrences(lines) + 1; + List newLines = buildNewLines(context, lines, occurrences, hash); + overwrite(errorLog, throwable, newLines); + } + + private void overwrite(Path errorLog, Throwable throwable, List newLines) { + try { + Files.write(errorLog, newLines, StandardOpenOption.TRUNCATE_EXISTING); + } catch (IOException e) { + throwable.addSuppressed(e); + Logger.getGlobal().log(Level.SEVERE, "Failed to log Plan error, see suppressed.", throwable); + } + } + + private List buildNewLines(ErrorContext context, List lines, int occurrences, String hash) { + Lists.Builder builder = Lists.builder(String.class) + .add(hash + " - Last occurred: " + getTimeStamp() + " Occurrences: " + occurrences); + // 5 contexts are enough. + if (occurrences <= 5) { + builder = buildContext(context, occurrences, builder); + } + int lineCount = lines.size(); + int firstContextLineIndex = findFirstContextLine(lines, lineCount); + return builder.addAll(lines.subList(firstContextLineIndex, lineCount)) + .build(); + } + + private String getTimeStamp() { + return formatters.get().iso8601NoClockLong().apply(System.currentTimeMillis()); + } + + private Lists.Builder buildContext(ErrorContext context, int occurrences, Lists.Builder builder) { + return builder.add("---- Context " + occurrences + " ----") + .add("Plan v" + versionChecker.get().getCurrentVersion()) + .add(serverProperties.get().getName() + " " + serverProperties.get().getVersion()) + .add("Server v" + serverProperties.get().getImplVersion()) + .add("") + .addAll(context.toLines()) + .add(""); + } + + private void logAfterReadError(Path errorLog, Throwable throwable, ErrorContext context, String hash) { + logger.error("Failed to read " + errorLog + " deleting file"); + try { + Files.deleteIfExists(errorLog); + } catch (IOException ioException) { + logger.error("Failed to delete " + errorLog); + } + logNew(errorLog, throwable, context, hash); + } + + private int getOccurrences(List lines) { + String occurLine = lines.get(0); + return Integer.parseInt(StringUtils.splitByWholeSeparator(occurLine, ": ")[2].trim()); + } + + private int findFirstContextLine(List lines, int lineCount) { + int firstContextLineIndex = 0; + for (int i = 0; i < lineCount; i++) { + if (lines.get(i).contains("---- Context")) { + firstContextLineIndex = i; + break; + } + } + return firstContextLineIndex; + } + + private void logToConsole(L level, Path errorLog, Throwable throwable, ErrorContext context) { + String errorName = throwable.getClass().getSimpleName(); + String errorMsg = throwable.getMessage(); + String errorLocation = errorLog.toString(); + logger.log(level, + "Ran into " + errorName + " - logged to " + errorLocation, + "(INCLUDE CONTENTS OF THE FILE IN ANY REPORTS)", + context.getWhatToDo().map(td -> "What to do: " + td).orElse("Error msg: \"" + errorMsg + "\"") + ); + } + + private void logNew(Path errorLog, Throwable throwable, ErrorContext context, String hash) { + List stacktrace = buildReadableStacktrace(new ArrayList<>(), throwable); + List lines = Lists.builder(String.class) + .add(hash + " - Last occurred: " + getTimeStamp() + " Occurrences: 1") + .apply(builder -> this.buildContext(context, 1, builder)) + .add("---- Stacktrace ----") + .addAll(stacktrace) + .build(); + writeNew(errorLog, throwable, lines); + } + + private void writeNew(Path errorLog, Throwable throwable, List lines) { + try { + Files.createDirectories(errorLog.getParent()); + Files.write(errorLog, lines, StandardOpenOption.CREATE_NEW, StandardOpenOption.APPEND); + } catch (IOException e) { + throwable.addSuppressed(e); + Logger.getGlobal().log(Level.SEVERE, "Failed to log Plan error, see suppressed.", throwable); + } + } + + private String hash(Throwable e) { + int seed = 0; + Throwable cause = e; + String previousLine = null; + while (cause != null) { + for (StackTraceElement element : cause.getStackTrace()) { + String asLine = element.toString(); + if (asLine.equals(previousLine)) continue; + if (seed == 0) { + seed = asLine.hashCode(); + } else { + seed *= asLine.hashCode(); + } + previousLine = asLine; + } + cause = cause.getCause(); + } + return DigestUtils.sha256Hex(Integer.toString(seed)).substring(0, 10); + } + + private List buildReadableStacktrace(List trace, Throwable e) { + trace.add(e.toString()); + Deduplicator deduplicator = new Deduplicator(); + for (StackTraceElement element : e.getStackTrace()) { + String line = element.toString(); + deduplicator.addLines(trace, line); + } + deduplicator.addLeftoverDuplicateCountLine(trace); + Throwable[] suppressed = e.getSuppressed(); + if (suppressed.length > 0) { + for (Throwable suppressedThrowable : suppressed) { + trace.add(" Suppressed:"); + for (String line : buildReadableStacktrace(new ArrayList<>(), suppressedThrowable)) { + trace.add(" " + line); + } + } + } + Throwable cause = e.getCause(); + if (cause != null) { + trace.add("Caused by:"); + buildReadableStacktrace(trace, cause); + } + return trace; + } + + private static class Deduplicator { + private String previousLine = null; + private String lastDuplicate = null; + private int duplicateCount = 0; + + public void addLines(List trace, String line) { + if (duplicateCount > 0 && !line.equals(lastDuplicate)) { + String returnLine = " x " + duplicateCount; + duplicateCount = 1; + trace.add(returnLine); + trace.add(" " + line); + } else if (line.equals(lastDuplicate)) { + duplicateCount++; + } else if (line.equals(previousLine)) { + lastDuplicate = line; + duplicateCount = 2; + } else { + previousLine = line; + trace.add(" " + line); + } + } + + public void addLeftoverDuplicateCountLine(List trace) { + if (duplicateCount > 0) { + trace.add(" x " + duplicateCount); + } + } + } +} diff --git a/Plan/common/src/main/java/com/djrapitops/plan/version/VersionChecker.java b/Plan/common/src/main/java/com/djrapitops/plan/version/VersionChecker.java index 0e13ba065..4d20d0c17 100644 --- a/Plan/common/src/main/java/com/djrapitops/plan/version/VersionChecker.java +++ b/Plan/common/src/main/java/com/djrapitops/plan/version/VersionChecker.java @@ -16,7 +16,6 @@ */ package com.djrapitops.plan.version; -import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.SubSystem; import com.djrapitops.plan.settings.config.PlanConfig; import com.djrapitops.plan.settings.config.paths.PluginSettings; @@ -29,6 +28,7 @@ import com.djrapitops.plugin.api.utility.Version; import com.djrapitops.plugin.logging.L; import com.djrapitops.plugin.logging.console.PluginLogger; import com.djrapitops.plugin.task.AbsRunnable; +import com.djrapitops.plugin.task.RunnableFactory; import javax.inject.Inject; import javax.inject.Named; @@ -49,8 +49,8 @@ public class VersionChecker implements SubSystem { private final Locale locale; private final PlanConfig config; private final PluginLogger logger; + private final RunnableFactory runnableFactory; private final ErrorLogger errorLogger; - private final PlanPlugin plugin; private VersionInfo newVersionAvailable; @@ -60,15 +60,15 @@ public class VersionChecker implements SubSystem { Locale locale, PlanConfig config, PluginLogger logger, - ErrorLogger errorLogger, - PlanPlugin plugin + RunnableFactory runnableFactory, + ErrorLogger errorLogger ) { this.currentVersion = currentVersion; this.locale = locale; this.config = config; this.logger = logger; + this.runnableFactory = runnableFactory; this.errorLogger = errorLogger; - this.plugin = plugin; } public boolean isNewVersionAvailable() { @@ -108,7 +108,7 @@ public class VersionChecker implements SubSystem { if (config.isFalse(PluginSettings.CHECK_FOR_UPDATES)) { return; } - plugin.getRunnableFactory().create("VersionChecker", new AbsRunnable() { + runnableFactory.create("VersionChecker", new AbsRunnable() { @Override public void run() { checkForUpdates(); diff --git a/Plan/common/src/test/java/com/djrapitops/plan/gathering/ShutdownSaveTest.java b/Plan/common/src/test/java/com/djrapitops/plan/gathering/ShutdownSaveTest.java index 03399ff98..e414aa52e 100644 --- a/Plan/common/src/test/java/com/djrapitops/plan/gathering/ShutdownSaveTest.java +++ b/Plan/common/src/test/java/com/djrapitops/plan/gathering/ShutdownSaveTest.java @@ -66,12 +66,14 @@ class ShutdownSaveTest { @BeforeEach void setupShutdownSaveObject(@TempDir Path temporaryFolder) throws Exception { - PlanPluginComponent pluginComponent = DaggerPlanPluginComponent.builder().plan( - PlanPluginMocker.setUp() - .withDataFolder(temporaryFolder.resolve("ShutdownSaveTest").toFile()) - .withLogging() - .getPlanMock() - ).build(); + PlanPluginComponent pluginComponent = DaggerPlanPluginComponent.builder() + .bindTemporaryDirectory(temporaryFolder) + .plan( + PlanPluginMocker.setUp() + .withDataFolder(temporaryFolder.resolve("ShutdownSaveTest").toFile()) + .withLogging() + .getPlanMock() + ).build(); PlanSystem system = pluginComponent.system(); database = system.getDatabaseSystem().getSqLiteFactory().usingFileCalled("test"); diff --git a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTest.java b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTest.java index 41facc525..d5e935fc4 100644 --- a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTest.java +++ b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTest.java @@ -131,11 +131,11 @@ public interface DatabaseTest extends DatabaseTestPreparer { TestPluginLogger logger = new TestPluginLogger(); new DBCleanTask( - system().getConfigSystem().getConfig(), + config(), new Locale(), - system().getDatabaseSystem(), - new QuerySvc(system().getDatabaseSystem(), system().getServerInfo(), null), - system().getServerInfo(), + dbSystem(), + new QuerySvc(dbSystem(), serverInfo(), null), + serverInfo(), logger, null ).cleanOldPlayers(db()); @@ -173,7 +173,7 @@ public interface DatabaseTest extends DatabaseTestPreparer { @Test default void configIsStoredInTheDatabase() { - PlanConfig config = system().getConfigSystem().getConfig(); + PlanConfig config = config(); db().executeTransaction(new StoreConfigTransaction(serverUUID(), config, System.currentTimeMillis())); @@ -187,7 +187,7 @@ public interface DatabaseTest extends DatabaseTestPreparer { configIsStoredInTheDatabase(); long savedMs = System.currentTimeMillis(); - PlanConfig config = system().getConfigSystem().getConfig(); + PlanConfig config = config(); db().executeTransaction(new StoreConfigTransaction(serverUUID(), config, System.currentTimeMillis())); @@ -256,7 +256,7 @@ public interface DatabaseTest extends DatabaseTestPreparer { String testSQL = SELECT + sql.dateToDayStamp(sql.epochSecondToDate(Long.toString((time + offset) / 1000))) + " as date"; System.out.println(testSQL); - String expected = system().getDeliveryUtilities().getFormatters().iso8601NoClockLong().apply(time); + String expected = deliveryUtilities().getFormatters().iso8601NoClockLong().apply(time); String result = db.query(new QueryAllStatement(testSQL) { @Override public String processResults(ResultSet set) throws SQLException { diff --git a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTestComponent.java b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTestComponent.java new file mode 100644 index 000000000..e26f75285 --- /dev/null +++ b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTestComponent.java @@ -0,0 +1,77 @@ +/* + * This file is part of Player Analytics (Plan). + * + * Plan is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License v3 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Plan 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 Plan. If not, see . + */ +package com.djrapitops.plan.storage.database; + +import com.djrapitops.plan.delivery.DeliveryUtilities; +import com.djrapitops.plan.identification.ServerInfo; +import com.djrapitops.plan.settings.ConfigSystem; +import com.djrapitops.plan.settings.config.PlanConfig; +import com.djrapitops.plan.storage.file.PlanFiles; +import dagger.BindsInstance; +import dagger.Component; +import utilities.DBPreparer; +import utilities.dagger.*; + +import javax.inject.Named; +import javax.inject.Singleton; +import java.nio.file.Path; + +@Singleton +@Component(modules = { + DBSystemModule.class, + TestSystemObjectProvidingModule.class, + + TestAPFModule.class, + PlanPluginModule.class, + PluginServerPropertiesModule.class, + PluginSuperClassBindingModule.class +}) +public interface DatabaseTestComponent extends DBPreparer.Dependencies { + + default void enable() { + configSystem().enable(); + dbSystem().enable(); + serverInfo().enable(); + } + + default void disable() { + serverInfo().disable(); + dbSystem().disable(); + configSystem().disable(); + } + + PlanConfig config(); + + ConfigSystem configSystem(); + + DBSystem dbSystem(); + + ServerInfo serverInfo(); + + DeliveryUtilities deliveryUtilities(); + + PlanFiles files(); + + @Component.Builder + interface Builder { + @BindsInstance + Builder bindTemporaryDirectory(@Named("tempDir") Path tempDir); + + DatabaseTestComponent build(); + } + +} diff --git a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTestPreparer.java b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTestPreparer.java index 2cf1960d5..91cf552e6 100644 --- a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTestPreparer.java +++ b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/DatabaseTestPreparer.java @@ -17,6 +17,9 @@ package com.djrapitops.plan.storage.database; import com.djrapitops.plan.PlanSystem; +import com.djrapitops.plan.delivery.DeliveryUtilities; +import com.djrapitops.plan.identification.ServerInfo; +import com.djrapitops.plan.settings.config.PlanConfig; import com.djrapitops.plan.storage.database.transactions.Executable; import com.djrapitops.plan.storage.database.transactions.Transaction; import utilities.TestConstants; @@ -33,8 +36,25 @@ public interface DatabaseTestPreparer { UUID serverUUID(); + @Deprecated PlanSystem system(); + default PlanConfig config() { + return system().getConfigSystem().getConfig(); + } + + default DBSystem dbSystem() { + return system().getDatabaseSystem(); + } + + default ServerInfo serverInfo() { + return system().getServerInfo(); + } + + default DeliveryUtilities deliveryUtilities() { + return system().getDeliveryUtilities(); + } + default void execute(Executable executable) { db().executeTransaction(new Transaction() { @Override diff --git a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/H2Test.java b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/H2Test.java index 88df440ca..730ad7be3 100644 --- a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/H2Test.java +++ b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/H2Test.java @@ -17,7 +17,10 @@ package com.djrapitops.plan.storage.database; import com.djrapitops.plan.PlanSystem; +import com.djrapitops.plan.delivery.DeliveryUtilities; import com.djrapitops.plan.identification.Server; +import com.djrapitops.plan.identification.ServerInfo; +import com.djrapitops.plan.settings.config.PlanConfig; import com.djrapitops.plan.storage.database.queries.*; import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction; import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction; @@ -28,15 +31,16 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import utilities.DBPreparer; import utilities.RandomData; -import utilities.mocks.PluginMockComponent; import java.nio.file.Path; import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; /** * Tests for the H2 database. @@ -61,13 +65,16 @@ public class H2Test implements DatabaseTest, private static final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500); - private static PlanSystem system; private static Database database; + private static DatabaseTestComponent component; @BeforeAll static void setupDatabase(@TempDir Path temp) throws Exception { - system = new PluginMockComponent(temp).getPlanSystem(); - database = new DBPreparer(system, TEST_PORT_NUMBER).prepareH2() + component = DaggerDatabaseTestComponent.builder() + .bindTemporaryDirectory(temp) + .build(); + component.enable(); + database = new DBPreparer(component, TEST_PORT_NUMBER).prepareH2() .orElseThrow(IllegalStateException::new); } @@ -101,7 +108,7 @@ public class H2Test implements DatabaseTest, database.close(); System.out.println("Database state after close: " + database.getState().name()); } - system.disable(); + component.disable(); } @Override @@ -111,11 +118,33 @@ public class H2Test implements DatabaseTest, @Override public UUID serverUUID() { - return system.getServerInfo().getServerUUID(); + return component.serverInfo().getServerUUID(); + } + + @Override + public PlanConfig config() { + return component.config(); + } + + @Override + public DBSystem dbSystem() { + return component.dbSystem(); + } + + @Override + public ServerInfo serverInfo() { + return component.serverInfo(); + } + + @Override + public DeliveryUtilities deliveryUtilities() { + return component.deliveryUtilities(); } @Override public PlanSystem system() { - return system; + PlanSystem mockSystem = Mockito.mock(PlanSystem.class); + when(mockSystem.getPlanFiles()).thenReturn(component.files()); + return mockSystem; } } diff --git a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/MySQLTest.java b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/MySQLTest.java index 6bd8727ed..fcb19416d 100644 --- a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/MySQLTest.java +++ b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/MySQLTest.java @@ -17,7 +17,10 @@ package com.djrapitops.plan.storage.database; import com.djrapitops.plan.PlanSystem; +import com.djrapitops.plan.delivery.DeliveryUtilities; import com.djrapitops.plan.identification.Server; +import com.djrapitops.plan.identification.ServerInfo; +import com.djrapitops.plan.settings.config.PlanConfig; import com.djrapitops.plan.storage.database.queries.*; import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction; import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction; @@ -29,16 +32,17 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import utilities.DBPreparer; import utilities.RandomData; -import utilities.mocks.PluginMockComponent; import java.nio.file.Path; import java.util.Optional; import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; /** * Tests for MySQL database. @@ -67,13 +71,16 @@ class MySQLTest implements DatabaseTest, private static final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500); - private static PlanSystem system; private static Database database; + private static DatabaseTestComponent component; @BeforeAll static void setupDatabase(@TempDir Path temp) throws Exception { - system = new PluginMockComponent(temp).getPlanSystem(); - Optional mysql = new DBPreparer(system, TEST_PORT_NUMBER).prepareMySQL(); + component = DaggerDatabaseTestComponent.builder() + .bindTemporaryDirectory(temp) + .build(); + component.enable(); + Optional mysql = new DBPreparer(component, TEST_PORT_NUMBER).prepareMySQL(); Assumptions.assumeTrue(mysql.isPresent()); database = mysql.get(); } @@ -104,7 +111,7 @@ class MySQLTest implements DatabaseTest, @AfterAll static void disableSystem() { if (database != null) database.close(); - system.disable(); + component.disable(); } @Override @@ -114,11 +121,33 @@ class MySQLTest implements DatabaseTest, @Override public UUID serverUUID() { - return system.getServerInfo().getServerUUID(); + return component.serverInfo().getServerUUID(); + } + + @Override + public PlanConfig config() { + return component.config(); + } + + @Override + public DBSystem dbSystem() { + return component.dbSystem(); + } + + @Override + public ServerInfo serverInfo() { + return component.serverInfo(); + } + + @Override + public DeliveryUtilities deliveryUtilities() { + return component.deliveryUtilities(); } @Override public PlanSystem system() { - return system; + PlanSystem mockSystem = Mockito.mock(PlanSystem.class); + when(mockSystem.getPlanFiles()).thenReturn(component.files()); + return mockSystem; } } diff --git a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/SQLiteTest.java b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/SQLiteTest.java index 1d2b5337e..ab7f35e29 100644 --- a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/SQLiteTest.java +++ b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/SQLiteTest.java @@ -17,7 +17,10 @@ package com.djrapitops.plan.storage.database; import com.djrapitops.plan.PlanSystem; +import com.djrapitops.plan.delivery.DeliveryUtilities; import com.djrapitops.plan.identification.Server; +import com.djrapitops.plan.identification.ServerInfo; +import com.djrapitops.plan.settings.config.PlanConfig; import com.djrapitops.plan.storage.database.queries.*; import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction; import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction; @@ -28,15 +31,16 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import utilities.DBPreparer; import utilities.RandomData; -import utilities.mocks.PluginMockComponent; import java.nio.file.Path; import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; /** * Tests for SQLite Database. @@ -61,13 +65,16 @@ public class SQLiteTest implements DatabaseTest, private static final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500); - private static PlanSystem system; private static Database database; + private static DatabaseTestComponent component; @BeforeAll static void setupDatabase(@TempDir Path temp) throws Exception { - system = new PluginMockComponent(temp).getPlanSystem(); - database = new DBPreparer(system, TEST_PORT_NUMBER).prepareSQLite() + component = DaggerDatabaseTestComponent.builder() + .bindTemporaryDirectory(temp) + .build(); + component.enable(); + database = new DBPreparer(component, TEST_PORT_NUMBER).prepareSQLite() .orElseThrow(IllegalStateException::new); } @@ -98,7 +105,7 @@ public class SQLiteTest implements DatabaseTest, @AfterAll static void disableSystem() { if (database != null) database.close(); - system.disable(); + component.disable(); } @Override @@ -108,11 +115,33 @@ public class SQLiteTest implements DatabaseTest, @Override public UUID serverUUID() { - return system.getServerInfo().getServerUUID(); + return component.serverInfo().getServerUUID(); + } + + @Override + public PlanConfig config() { + return component.config(); + } + + @Override + public DBSystem dbSystem() { + return component.dbSystem(); + } + + @Override + public ServerInfo serverInfo() { + return component.serverInfo(); + } + + @Override + public DeliveryUtilities deliveryUtilities() { + return component.deliveryUtilities(); } @Override public PlanSystem system() { - return system; + PlanSystem mockSystem = Mockito.mock(PlanSystem.class); + when(mockSystem.getPlanFiles()).thenReturn(component.files()); + return mockSystem; } } diff --git a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/queries/DatabaseBackupTest.java b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/queries/DatabaseBackupTest.java index 57caf63d0..d06c773f5 100644 --- a/Plan/common/src/test/java/com/djrapitops/plan/storage/database/queries/DatabaseBackupTest.java +++ b/Plan/common/src/test/java/com/djrapitops/plan/storage/database/queries/DatabaseBackupTest.java @@ -76,7 +76,7 @@ public interface DatabaseBackupTest extends DatabaseTestPreparer { default void testBackupAndRestoreSQLite() throws Exception { File tempFile = Files.createTempFile(system().getPlanFiles().getDataFolder().toPath(), "backup-", ".db").toFile(); tempFile.deleteOnExit(); - SQLiteDB backup = system().getDatabaseSystem().getSqLiteFactory().usingFile(tempFile); + SQLiteDB backup = dbSystem().getSqLiteFactory().usingFile(tempFile); backup.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService); try { backup.init(); @@ -103,7 +103,7 @@ public interface DatabaseBackupTest extends DatabaseTestPreparer { default void testBackupAndRestoreH2() throws Exception { File tempFile = Files.createTempFile(system().getPlanFiles().getDataFolder().toPath(), "backup-", ".db").toFile(); tempFile.deleteOnExit(); - H2DB backup = system().getDatabaseSystem().getH2Factory().usingFile(tempFile); + H2DB backup = dbSystem().getH2Factory().usingFile(tempFile); backup.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService); try { backup.init(); diff --git a/Plan/common/src/test/java/com/djrapitops/plan/utilities/logging/ErrorLoggerTest.java b/Plan/common/src/test/java/com/djrapitops/plan/utilities/logging/ErrorLoggerTest.java index 6953e16f9..8a4be31ec 100644 --- a/Plan/common/src/test/java/com/djrapitops/plan/utilities/logging/ErrorLoggerTest.java +++ b/Plan/common/src/test/java/com/djrapitops/plan/utilities/logging/ErrorLoggerTest.java @@ -49,7 +49,7 @@ class ErrorLoggerTest { PluginMockComponent component = new PluginMockComponent(dir); SYSTEM = component.getPlanSystem(); SYSTEM.enable(); - UNDER_TEST = SYSTEM.getErrorLogger(); + UNDER_TEST = component.getPluginErrorLogger(); LOGS_DIR = SYSTEM.getPlanFiles().getLogsDirectory(); } diff --git a/Plan/common/src/test/java/utilities/DBPreparer.java b/Plan/common/src/test/java/utilities/DBPreparer.java index 55afe4417..fdd516f34 100644 --- a/Plan/common/src/test/java/utilities/DBPreparer.java +++ b/Plan/common/src/test/java/utilities/DBPreparer.java @@ -34,11 +34,15 @@ import java.util.Optional; public class DBPreparer { - private final PlanSystem system; + private final Dependencies dependencies; private final int testPortNumber; public DBPreparer(PlanSystem system, int testPortNumber) { - this.system = system; + this(new PlanSystemAsDependencies(system), testPortNumber); + } + + public DBPreparer(Dependencies dependencies, int testPortNumber) { + this.dependencies = dependencies; this.testPortNumber = testPortNumber; } @@ -53,12 +57,12 @@ public class DBPreparer { } private SQLDB prepareDBByName(String dbName) throws EnableException { - PlanConfig config = system.getConfigSystem().getConfig(); + PlanConfig config = dependencies.config(); config.set(WebserverSettings.PORT, testPortNumber); config.set(DatabaseSettings.TYPE, dbName); - system.enable(); - DBSystem dbSystem = system.getDatabaseSystem(); + DBSystem dbSystem = dependencies.dbSystem(); + dbSystem.enable(); SQLDB db = (SQLDB) dbSystem.getActiveDatabaseByName(dbName); db.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService); db.init(); @@ -91,7 +95,7 @@ public class DBPreparer { } public Optional prepareMySQL() throws EnableException { - PlanConfig config = system.getConfigSystem().getConfig(); + PlanConfig config = dependencies.config(); Optional formattedDB = setUpMySQLSettings(config); if (formattedDB.isPresent()) { String formattedDatabase = formattedDB.get(); @@ -108,4 +112,29 @@ public class DBPreparer { } return Optional.empty(); } + + public interface Dependencies { + PlanConfig config(); + + DBSystem dbSystem(); + } + + @Deprecated + static class PlanSystemAsDependencies implements Dependencies { + private final PlanSystem system; + + PlanSystemAsDependencies(PlanSystem system) { + this.system = system; + } + + @Override + public PlanConfig config() { + return system.getConfigSystem().getConfig(); + } + + @Override + public DBSystem dbSystem() { + return system.getDatabaseSystem(); + } + } } diff --git a/Plan/common/src/test/java/utilities/dagger/DBSystemModule.java b/Plan/common/src/test/java/utilities/dagger/DBSystemModule.java new file mode 100644 index 000000000..4fd120fbc --- /dev/null +++ b/Plan/common/src/test/java/utilities/dagger/DBSystemModule.java @@ -0,0 +1,57 @@ +/* + * This file is part of Player Analytics (Plan). + * + * Plan is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License v3 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Plan 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 Plan. If not, see . + */ +package utilities.dagger; + +import com.djrapitops.plan.exceptions.EnableException; +import com.djrapitops.plan.settings.config.PlanConfig; +import com.djrapitops.plan.settings.config.paths.DatabaseSettings; +import com.djrapitops.plan.settings.locale.Locale; +import com.djrapitops.plan.storage.database.DBSystem; +import com.djrapitops.plan.storage.database.H2DB; +import com.djrapitops.plan.storage.database.MySQLDB; +import com.djrapitops.plan.storage.database.SQLiteDB; +import com.djrapitops.plugin.logging.console.PluginLogger; +import dagger.Module; +import dagger.Provides; + +import javax.inject.Singleton; + +@Module +public class DBSystemModule { + @Provides + @Singleton + DBSystem provideDatabaseSystem( + PlanConfig config, + Locale locale, + SQLiteDB.Factory sqLiteDB, + H2DB.Factory h2Factory, + MySQLDB mySQLDB, + PluginLogger logger + ) { + return new DBSystem(locale, sqLiteDB, h2Factory, logger) { + @Override + public void enable() throws EnableException { + databases.add(sqLiteDB.usingDefaultFile()); + databases.add(h2Factory.usingDefaultFile()); + databases.add(mySQLDB); + String dbType = config.get(DatabaseSettings.TYPE).toLowerCase().trim(); + db = getActiveDatabaseByName(dbType); + super.enable(); + } + }; + } +} diff --git a/Plan/common/src/test/java/utilities/dagger/PlanPluginComponent.java b/Plan/common/src/test/java/utilities/dagger/PlanPluginComponent.java index 82514dba3..5cf83e0ae 100644 --- a/Plan/common/src/test/java/utilities/dagger/PlanPluginComponent.java +++ b/Plan/common/src/test/java/utilities/dagger/PlanPluginComponent.java @@ -19,13 +19,14 @@ package utilities.dagger; import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.PlanSystem; import com.djrapitops.plan.commands.PlanCommand; -import com.djrapitops.plan.modules.APFModule; import com.djrapitops.plan.modules.PlaceholderModule; -import com.djrapitops.plan.modules.SystemObjectProvidingModule; +import com.djrapitops.plan.utilities.logging.PluginErrorLogger; import dagger.BindsInstance; import dagger.Component; +import javax.inject.Named; import javax.inject.Singleton; +import java.nio.file.Path; /** * Dagger component for {@link com.djrapitops.plan.PlanPlugin} based Plan system. @@ -35,20 +36,25 @@ import javax.inject.Singleton; @Singleton @Component(modules = { PlanPluginModule.class, - SystemObjectProvidingModule.class, - APFModule.class, + TestSystemObjectProvidingModule.class, + TestAPFModule.class, PlaceholderModule.class, PluginServerPropertiesModule.class, - PluginSuperClassBindingModule.class + PluginSuperClassBindingModule.class, + DBSystemModule.class }) public interface PlanPluginComponent { PlanCommand planCommand(); PlanSystem system(); + PluginErrorLogger pluginErrorLogger(); + @Component.Builder interface Builder { + @BindsInstance + Builder bindTemporaryDirectory(@Named("tempDir") Path tempDir); @BindsInstance Builder plan(PlanPlugin plan); diff --git a/Plan/common/src/test/java/utilities/dagger/PluginSuperClassBindingModule.java b/Plan/common/src/test/java/utilities/dagger/PluginSuperClassBindingModule.java index 4a0c6235d..6550154ee 100644 --- a/Plan/common/src/test/java/utilities/dagger/PluginSuperClassBindingModule.java +++ b/Plan/common/src/test/java/utilities/dagger/PluginSuperClassBindingModule.java @@ -18,18 +18,9 @@ package utilities.dagger; import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.TaskSystem; -import com.djrapitops.plan.exceptions.EnableException; import com.djrapitops.plan.gathering.ServerSensor; import com.djrapitops.plan.gathering.listeners.ListenerSystem; import com.djrapitops.plan.processing.Processing; -import com.djrapitops.plan.settings.config.PlanConfig; -import com.djrapitops.plan.settings.config.paths.DatabaseSettings; -import com.djrapitops.plan.settings.locale.Locale; -import com.djrapitops.plan.storage.database.DBSystem; -import com.djrapitops.plan.storage.database.H2DB; -import com.djrapitops.plan.storage.database.MySQLDB; -import com.djrapitops.plan.storage.database.SQLiteDB; -import com.djrapitops.plugin.logging.console.PluginLogger; import com.djrapitops.plugin.task.RunnableFactory; import dagger.Module; import dagger.Provides; @@ -49,29 +40,6 @@ import static org.mockito.Mockito.when; @Module public class PluginSuperClassBindingModule { - @Provides - @Singleton - DBSystem provideDatabaseSystem( - PlanConfig config, - Locale locale, - SQLiteDB.Factory sqLiteDB, - H2DB.Factory h2Factory, - MySQLDB mySQLDB, - PluginLogger logger - ) { - return new DBSystem(locale, sqLiteDB, h2Factory, logger) { - @Override - public void enable() throws EnableException { - databases.add(sqLiteDB.usingDefaultFile()); - databases.add(h2Factory.usingDefaultFile()); - databases.add(mySQLDB); - String dbType = config.get(DatabaseSettings.TYPE).toLowerCase().trim(); - db = getActiveDatabaseByName(dbType); - super.enable(); - } - }; - } - @Provides @Singleton TaskSystem provideTaskSystem(RunnableFactory runnableFactory) { diff --git a/Plan/common/src/test/java/utilities/dagger/TestAPFModule.java b/Plan/common/src/test/java/utilities/dagger/TestAPFModule.java new file mode 100644 index 000000000..58f1c7242 --- /dev/null +++ b/Plan/common/src/test/java/utilities/dagger/TestAPFModule.java @@ -0,0 +1,83 @@ +/* + * This file is part of Player Analytics (Plan). + * + * Plan is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License v3 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Plan 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 Plan. If not, see . + */ +package utilities.dagger; + +import com.djrapitops.plan.utilities.logging.ErrorLogger; +import com.djrapitops.plugin.benchmarking.Timings; +import com.djrapitops.plugin.command.ColorScheme; +import com.djrapitops.plugin.logging.console.PluginLogger; +import com.djrapitops.plugin.logging.console.TestPluginLogger; +import com.djrapitops.plugin.logging.debug.ConsoleDebugLogger; +import com.djrapitops.plugin.logging.debug.DebugLogger; +import com.djrapitops.plugin.logging.error.ErrorHandler; +import com.djrapitops.plugin.task.RunnableFactory; +import dagger.Module; +import dagger.Provides; +import utilities.mocks.objects.TestRunnableFactory; + +import javax.inject.Named; +import javax.inject.Singleton; + +@Module +public class TestAPFModule { + + @Provides + @Named("currentVersion") + @Singleton + String provideCurrentVersion() { + return "0.0.1"; + } + + @Provides + @Singleton + ColorScheme provideColorScheme() { + return new ColorScheme( + "", "", "" + ); + } + + @Provides + @Singleton + DebugLogger provideDebugLogger(PluginLogger logger) { + return new ConsoleDebugLogger(logger); + } + + @Provides + @Singleton + PluginLogger providePluginLogger() { + return new TestPluginLogger(); + } + + @Provides + @Singleton + ErrorHandler provideErrorHandler(ErrorLogger errorLogger) { + return errorLogger; + } + + @Provides + @Singleton + Timings provideTimings(DebugLogger debugLogger) { + return new Timings(debugLogger); + } + + @Provides + @Singleton + RunnableFactory provideRunnableFactory() { + return new TestRunnableFactory(); + } + +} diff --git a/Plan/common/src/test/java/utilities/dagger/TestSystemObjectProvidingModule.java b/Plan/common/src/test/java/utilities/dagger/TestSystemObjectProvidingModule.java new file mode 100644 index 000000000..244c221b0 --- /dev/null +++ b/Plan/common/src/test/java/utilities/dagger/TestSystemObjectProvidingModule.java @@ -0,0 +1,82 @@ +/* + * This file is part of Player Analytics (Plan). + * + * Plan is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License v3 as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Plan 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 Plan. If not, see . + */ +package utilities.dagger; + +import com.djrapitops.plan.settings.config.ExtensionSettings; +import com.djrapitops.plan.settings.config.PlanConfig; +import com.djrapitops.plan.settings.locale.Locale; +import com.djrapitops.plan.settings.locale.LocaleSystem; +import com.djrapitops.plan.storage.file.JarResource; +import com.djrapitops.plan.utilities.logging.ErrorLogger; +import dagger.Module; +import dagger.Provides; +import utilities.TestResources; + +import javax.inject.Named; +import javax.inject.Singleton; +import java.io.File; +import java.io.FileInputStream; +import java.nio.file.Path; +import java.util.function.Predicate; + +@Module +public class TestSystemObjectProvidingModule { + + @Provides + @Singleton + Locale provideLocale(LocaleSystem localeSystem) { + return localeSystem.getLocale(); + } + + @Provides + @Singleton + ExtensionSettings providePluginsConfigSection(PlanConfig config) { + return config.getExtensionSettings(); + } + + @Provides + @Singleton + @Named("isExtensionEnabled") + Predicate provideExtensionEnabledConfigCheck(PlanConfig config) { + return config.getExtensionSettings()::isEnabled; + } + + @Provides + @Singleton + JarResource.StreamFunction provideJarStreamFunction(@Named("tempDir") Path tempDir) { + return resource -> { + File copyTo = tempDir.resolve(resource).toFile(); + TestResources.copyResourceIntoFile(copyTo, "/" + resource); + return new FileInputStream(copyTo); + }; + } + + @Provides + @Singleton + @Named("dataFolder") + File provideDataFolder(@Named("tempDir") Path tempDir) { + return tempDir.toFile(); + } + + @Provides + @Singleton + ErrorLogger provideErrorLogger() { + return (level, throwable, context) -> { + throw new AssertionError("Test had an Exception: " + level.name() + " " + throwable.toString() + " " + context, throwable); + }; + } +} diff --git a/Plan/common/src/test/java/utilities/mocks/PluginMockComponent.java b/Plan/common/src/test/java/utilities/mocks/PluginMockComponent.java index 8b3b69e69..9814f0a87 100644 --- a/Plan/common/src/test/java/utilities/mocks/PluginMockComponent.java +++ b/Plan/common/src/test/java/utilities/mocks/PluginMockComponent.java @@ -18,6 +18,7 @@ package utilities.mocks; import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.PlanSystem; +import com.djrapitops.plan.utilities.logging.PluginErrorLogger; import utilities.dagger.DaggerPlanPluginComponent; import utilities.dagger.PlanPluginComponent; @@ -50,9 +51,20 @@ public class PluginMockComponent { } public PlanSystem getPlanSystem() throws Exception { - if (component == null) { - component = DaggerPlanPluginComponent.builder().plan(getPlanMock()).build(); - } + initComponent(); return component.system(); } + + private void initComponent() throws Exception { + if (component == null) { + component = DaggerPlanPluginComponent.builder() + .bindTemporaryDirectory(tempDir) + .plan(getPlanMock()).build(); + } + } + + public PluginErrorLogger getPluginErrorLogger() throws Exception { + initComponent(); + return component.pluginErrorLogger(); + } } \ No newline at end of file diff --git a/Plan/nukkit/src/main/java/com/djrapitops/plan/gathering/listeners/nukkit/NukkitAFKListener.java b/Plan/nukkit/src/main/java/com/djrapitops/plan/gathering/listeners/nukkit/NukkitAFKListener.java index 021850395..5eee9b0e3 100644 --- a/Plan/nukkit/src/main/java/com/djrapitops/plan/gathering/listeners/nukkit/NukkitAFKListener.java +++ b/Plan/nukkit/src/main/java/com/djrapitops/plan/gathering/listeners/nukkit/NukkitAFKListener.java @@ -50,7 +50,10 @@ public class NukkitAFKListener implements Listener { private final ErrorLogger errorLogger; @Inject - public NukkitAFKListener(PlanConfig config, ErrorLogger errorLogger) { + public NukkitAFKListener( + PlanConfig config, + ErrorLogger errorLogger + ) { this.errorLogger = errorLogger; this.ignorePermissionInfo = new HashMap<>();