Full System no longer required for database tests

- Extracted ErrorLogger interface
- Created a new Component for Database tests
- Added TestAPFModule and TestSystemObjectBindingModule
- Database tests no longer enable the full system

Affects issues:
- Close #1401
This commit is contained in:
Rsl1122 2020-11-08 11:46:44 +02:00
parent c8f1585ee1
commit 6effdbec39
25 changed files with 837 additions and 359 deletions

View File

@ -37,7 +37,11 @@ public class BukkitCommand implements CommandExecutor, TabCompleter {
private final ErrorLogger errorLogger; private final ErrorLogger errorLogger;
private final Subcommand command; private final Subcommand command;
public BukkitCommand(RunnableFactory runnableFactory, ErrorLogger errorLogger, Subcommand command) { public BukkitCommand(
RunnableFactory runnableFactory,
ErrorLogger errorLogger,
Subcommand command
) {
this.runnableFactory = runnableFactory; this.runnableFactory = runnableFactory;
this.errorLogger = errorLogger; this.errorLogger = errorLogger;
this.command = command; this.command = command;

View File

@ -41,8 +41,8 @@ public class BungeeCommand extends Command implements TabExecutor {
public BungeeCommand( public BungeeCommand(
RunnableFactory runnableFactory, RunnableFactory runnableFactory,
ErrorLogger errorLogger, Subcommand command, ErrorLogger errorLogger,
String name Subcommand command, String name
) { ) {
super(name); super(name);
this.runnableFactory = runnableFactory; this.runnableFactory = runnableFactory;

View File

@ -293,6 +293,13 @@ public class PlanSystem implements SubSystem {
return extensionService; 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() { public ErrorLogger getErrorLogger() {
return errorLogger; return errorLogger;
} }

View File

@ -22,6 +22,8 @@ import com.djrapitops.plan.settings.config.PlanConfig;
import com.djrapitops.plan.settings.locale.Locale; import com.djrapitops.plan.settings.locale.Locale;
import com.djrapitops.plan.settings.locale.LocaleSystem; import com.djrapitops.plan.settings.locale.LocaleSystem;
import com.djrapitops.plan.storage.file.JarResource; 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.Module;
import dagger.Provides; import dagger.Provides;
@ -70,4 +72,10 @@ public class SystemObjectProvidingModule {
return plugin.getDataFolder(); return plugin.getDataFolder();
} }
@Provides
@Singleton
ErrorLogger provideErrorLogger(PluginErrorLogger errorLogger) {
return errorLogger;
}
} }

View File

@ -81,4 +81,12 @@ public class ErrorContext implements Serializable {
return context; return context;
} }
} }
@Override
public String toString() {
return "ErrorContext{" +
"related=" + related +
", whatToDo='" + whatToDo + '\'' +
'}';
}
} }

View File

@ -16,284 +16,22 @@
*/ */
package com.djrapitops.plan.utilities.logging; 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.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.L;
import com.djrapitops.plugin.logging.console.PluginLogger;
import com.djrapitops.plugin.logging.error.ErrorHandler; 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; public interface ErrorLogger extends ErrorHandler {
import javax.inject.Singleton; default <T extends ExceptionWithContext> void log(L level, T throwable) {
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> serverProperties;
private final Lazy<VersionChecker> versionChecker;
private final Lazy<Formatters> formatters;
@Inject
public ErrorLogger(
PlanPlugin plugin,
PluginLogger logger,
PlanFiles files,
Lazy<ServerProperties> serverProperties,
Lazy<VersionChecker> versionChecker,
Lazy<Formatters> formatters
) {
this.plugin = plugin;
this.logger = logger;
this.files = files;
this.serverProperties = serverProperties;
this.versionChecker = versionChecker;
this.formatters = formatters;
}
public <T extends ExceptionWithContext> void log(L level, T throwable) {
log(level, (Throwable) throwable, throwable.getContext().orElse(ErrorContext.builder().related("Missing Context").build())); log(level, (Throwable) throwable, throwable.getContext().orElse(ErrorContext.builder().related("Missing Context").build()));
} }
public void log(L level, Throwable throwable, ErrorContext context) { 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<String> lines;
try (Stream<String> read = Files.lines(errorLog)) {
lines = read.collect(Collectors.toList());
} catch (IOException e) {
logAfterReadError(errorLog, throwable, context, hash);
return;
}
int occurrences = getOccurrences(lines) + 1;
List<String> newLines = buildNewLines(context, lines, occurrences, hash);
overwrite(errorLog, throwable, newLines);
}
private void overwrite(Path errorLog, Throwable throwable, List<String> 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<String> buildNewLines(ErrorContext context, List<String> lines, int occurrences, String hash) {
Lists.Builder<String> 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<String> buildContext(ErrorContext context, int occurrences, Lists.Builder<String> 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<String> lines) {
String occurLine = lines.get(0);
return Integer.parseInt(StringUtils.splitByWholeSeparator(occurLine, ": ")[2].trim());
}
private int findFirstContextLine(List<String> 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<String> stacktrace = buildReadableStacktrace(new ArrayList<>(), throwable);
List<String> 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<String> 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);
}
}
@Override @Override
@Deprecated @Deprecated
public void log(L level, Class caughtBy, Throwable throwable) { default void log(L level, Class caughtBy, Throwable throwable) {
log(level, throwable, ErrorContext.builder() log(level, throwable, ErrorContext.builder()
.related("Caught by " + caughtBy.getName()) .related("Caught by " + caughtBy.getName())
.build()); .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<String> buildReadableStacktrace(List<String> 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<String> 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<String> trace) {
if (duplicateCount > 0) {
trace.add(" x " + duplicateCount);
}
}
}
} }

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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> serverProperties;
private final Lazy<VersionChecker> versionChecker;
private final Lazy<Formatters> formatters;
@Inject
public PluginErrorLogger(
PlanPlugin plugin,
PluginLogger logger,
PlanFiles files,
Lazy<ServerProperties> serverProperties,
Lazy<VersionChecker> versionChecker,
Lazy<Formatters> 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<String> lines;
try (Stream<String> read = Files.lines(errorLog)) {
lines = read.collect(Collectors.toList());
} catch (IOException e) {
logAfterReadError(errorLog, throwable, context, hash);
return;
}
int occurrences = getOccurrences(lines) + 1;
List<String> newLines = buildNewLines(context, lines, occurrences, hash);
overwrite(errorLog, throwable, newLines);
}
private void overwrite(Path errorLog, Throwable throwable, List<String> 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<String> buildNewLines(ErrorContext context, List<String> lines, int occurrences, String hash) {
Lists.Builder<String> 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<String> buildContext(ErrorContext context, int occurrences, Lists.Builder<String> 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<String> lines) {
String occurLine = lines.get(0);
return Integer.parseInt(StringUtils.splitByWholeSeparator(occurLine, ": ")[2].trim());
}
private int findFirstContextLine(List<String> 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<String> stacktrace = buildReadableStacktrace(new ArrayList<>(), throwable);
List<String> 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<String> 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<String> buildReadableStacktrace(List<String> 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<String> 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<String> trace) {
if (duplicateCount > 0) {
trace.add(" x " + duplicateCount);
}
}
}
}

View File

@ -16,7 +16,6 @@
*/ */
package com.djrapitops.plan.version; package com.djrapitops.plan.version;
import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.SubSystem; import com.djrapitops.plan.SubSystem;
import com.djrapitops.plan.settings.config.PlanConfig; import com.djrapitops.plan.settings.config.PlanConfig;
import com.djrapitops.plan.settings.config.paths.PluginSettings; 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.L;
import com.djrapitops.plugin.logging.console.PluginLogger; import com.djrapitops.plugin.logging.console.PluginLogger;
import com.djrapitops.plugin.task.AbsRunnable; import com.djrapitops.plugin.task.AbsRunnable;
import com.djrapitops.plugin.task.RunnableFactory;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -49,8 +49,8 @@ public class VersionChecker implements SubSystem {
private final Locale locale; private final Locale locale;
private final PlanConfig config; private final PlanConfig config;
private final PluginLogger logger; private final PluginLogger logger;
private final RunnableFactory runnableFactory;
private final ErrorLogger errorLogger; private final ErrorLogger errorLogger;
private final PlanPlugin plugin;
private VersionInfo newVersionAvailable; private VersionInfo newVersionAvailable;
@ -60,15 +60,15 @@ public class VersionChecker implements SubSystem {
Locale locale, Locale locale,
PlanConfig config, PlanConfig config,
PluginLogger logger, PluginLogger logger,
ErrorLogger errorLogger, RunnableFactory runnableFactory,
PlanPlugin plugin ErrorLogger errorLogger
) { ) {
this.currentVersion = currentVersion; this.currentVersion = currentVersion;
this.locale = locale; this.locale = locale;
this.config = config; this.config = config;
this.logger = logger; this.logger = logger;
this.runnableFactory = runnableFactory;
this.errorLogger = errorLogger; this.errorLogger = errorLogger;
this.plugin = plugin;
} }
public boolean isNewVersionAvailable() { public boolean isNewVersionAvailable() {
@ -108,7 +108,7 @@ public class VersionChecker implements SubSystem {
if (config.isFalse(PluginSettings.CHECK_FOR_UPDATES)) { if (config.isFalse(PluginSettings.CHECK_FOR_UPDATES)) {
return; return;
} }
plugin.getRunnableFactory().create("VersionChecker", new AbsRunnable() { runnableFactory.create("VersionChecker", new AbsRunnable() {
@Override @Override
public void run() { public void run() {
checkForUpdates(); checkForUpdates();

View File

@ -66,12 +66,14 @@ class ShutdownSaveTest {
@BeforeEach @BeforeEach
void setupShutdownSaveObject(@TempDir Path temporaryFolder) throws Exception { void setupShutdownSaveObject(@TempDir Path temporaryFolder) throws Exception {
PlanPluginComponent pluginComponent = DaggerPlanPluginComponent.builder().plan( PlanPluginComponent pluginComponent = DaggerPlanPluginComponent.builder()
PlanPluginMocker.setUp() .bindTemporaryDirectory(temporaryFolder)
.withDataFolder(temporaryFolder.resolve("ShutdownSaveTest").toFile()) .plan(
.withLogging() PlanPluginMocker.setUp()
.getPlanMock() .withDataFolder(temporaryFolder.resolve("ShutdownSaveTest").toFile())
).build(); .withLogging()
.getPlanMock()
).build();
PlanSystem system = pluginComponent.system(); PlanSystem system = pluginComponent.system();
database = system.getDatabaseSystem().getSqLiteFactory().usingFileCalled("test"); database = system.getDatabaseSystem().getSqLiteFactory().usingFileCalled("test");

View File

@ -131,11 +131,11 @@ public interface DatabaseTest extends DatabaseTestPreparer {
TestPluginLogger logger = new TestPluginLogger(); TestPluginLogger logger = new TestPluginLogger();
new DBCleanTask( new DBCleanTask(
system().getConfigSystem().getConfig(), config(),
new Locale(), new Locale(),
system().getDatabaseSystem(), dbSystem(),
new QuerySvc(system().getDatabaseSystem(), system().getServerInfo(), null), new QuerySvc(dbSystem(), serverInfo(), null),
system().getServerInfo(), serverInfo(),
logger, logger,
null null
).cleanOldPlayers(db()); ).cleanOldPlayers(db());
@ -173,7 +173,7 @@ public interface DatabaseTest extends DatabaseTestPreparer {
@Test @Test
default void configIsStoredInTheDatabase() { default void configIsStoredInTheDatabase() {
PlanConfig config = system().getConfigSystem().getConfig(); PlanConfig config = config();
db().executeTransaction(new StoreConfigTransaction(serverUUID(), config, System.currentTimeMillis())); db().executeTransaction(new StoreConfigTransaction(serverUUID(), config, System.currentTimeMillis()));
@ -187,7 +187,7 @@ public interface DatabaseTest extends DatabaseTestPreparer {
configIsStoredInTheDatabase(); configIsStoredInTheDatabase();
long savedMs = System.currentTimeMillis(); long savedMs = System.currentTimeMillis();
PlanConfig config = system().getConfigSystem().getConfig(); PlanConfig config = config();
db().executeTransaction(new StoreConfigTransaction(serverUUID(), config, System.currentTimeMillis())); 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"; String testSQL = SELECT + sql.dateToDayStamp(sql.epochSecondToDate(Long.toString((time + offset) / 1000))) + " as date";
System.out.println(testSQL); 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<String>(testSQL) { String result = db.query(new QueryAllStatement<String>(testSQL) {
@Override @Override
public String processResults(ResultSet set) throws SQLException { public String processResults(ResultSet set) throws SQLException {

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@ -17,6 +17,9 @@
package com.djrapitops.plan.storage.database; package com.djrapitops.plan.storage.database;
import com.djrapitops.plan.PlanSystem; 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.Executable;
import com.djrapitops.plan.storage.database.transactions.Transaction; import com.djrapitops.plan.storage.database.transactions.Transaction;
import utilities.TestConstants; import utilities.TestConstants;
@ -33,8 +36,25 @@ public interface DatabaseTestPreparer {
UUID serverUUID(); UUID serverUUID();
@Deprecated
PlanSystem system(); 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) { default void execute(Executable executable) {
db().executeTransaction(new Transaction() { db().executeTransaction(new Transaction() {
@Override @Override

View File

@ -17,7 +17,10 @@
package com.djrapitops.plan.storage.database; package com.djrapitops.plan.storage.database;
import com.djrapitops.plan.PlanSystem; import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.delivery.DeliveryUtilities;
import com.djrapitops.plan.identification.Server; 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.queries.*;
import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction; import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction;
import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction; 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.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import utilities.DBPreparer; import utilities.DBPreparer;
import utilities.RandomData; import utilities.RandomData;
import utilities.mocks.PluginMockComponent;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.UUID; import java.util.UUID;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
/** /**
* Tests for the H2 database. * 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 final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500);
private static PlanSystem system;
private static Database database; private static Database database;
private static DatabaseTestComponent component;
@BeforeAll @BeforeAll
static void setupDatabase(@TempDir Path temp) throws Exception { static void setupDatabase(@TempDir Path temp) throws Exception {
system = new PluginMockComponent(temp).getPlanSystem(); component = DaggerDatabaseTestComponent.builder()
database = new DBPreparer(system, TEST_PORT_NUMBER).prepareH2() .bindTemporaryDirectory(temp)
.build();
component.enable();
database = new DBPreparer(component, TEST_PORT_NUMBER).prepareH2()
.orElseThrow(IllegalStateException::new); .orElseThrow(IllegalStateException::new);
} }
@ -101,7 +108,7 @@ public class H2Test implements DatabaseTest,
database.close(); database.close();
System.out.println("Database state after close: " + database.getState().name()); System.out.println("Database state after close: " + database.getState().name());
} }
system.disable(); component.disable();
} }
@Override @Override
@ -111,11 +118,33 @@ public class H2Test implements DatabaseTest,
@Override @Override
public UUID serverUUID() { 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 @Override
public PlanSystem system() { public PlanSystem system() {
return system; PlanSystem mockSystem = Mockito.mock(PlanSystem.class);
when(mockSystem.getPlanFiles()).thenReturn(component.files());
return mockSystem;
} }
} }

View File

@ -17,7 +17,10 @@
package com.djrapitops.plan.storage.database; package com.djrapitops.plan.storage.database;
import com.djrapitops.plan.PlanSystem; import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.delivery.DeliveryUtilities;
import com.djrapitops.plan.identification.Server; 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.queries.*;
import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction; import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction;
import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction; 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.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import utilities.DBPreparer; import utilities.DBPreparer;
import utilities.RandomData; import utilities.RandomData;
import utilities.mocks.PluginMockComponent;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
/** /**
* Tests for MySQL database. * 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 final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500);
private static PlanSystem system;
private static Database database; private static Database database;
private static DatabaseTestComponent component;
@BeforeAll @BeforeAll
static void setupDatabase(@TempDir Path temp) throws Exception { static void setupDatabase(@TempDir Path temp) throws Exception {
system = new PluginMockComponent(temp).getPlanSystem(); component = DaggerDatabaseTestComponent.builder()
Optional<Database> mysql = new DBPreparer(system, TEST_PORT_NUMBER).prepareMySQL(); .bindTemporaryDirectory(temp)
.build();
component.enable();
Optional<Database> mysql = new DBPreparer(component, TEST_PORT_NUMBER).prepareMySQL();
Assumptions.assumeTrue(mysql.isPresent()); Assumptions.assumeTrue(mysql.isPresent());
database = mysql.get(); database = mysql.get();
} }
@ -104,7 +111,7 @@ class MySQLTest implements DatabaseTest,
@AfterAll @AfterAll
static void disableSystem() { static void disableSystem() {
if (database != null) database.close(); if (database != null) database.close();
system.disable(); component.disable();
} }
@Override @Override
@ -114,11 +121,33 @@ class MySQLTest implements DatabaseTest,
@Override @Override
public UUID serverUUID() { 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 @Override
public PlanSystem system() { public PlanSystem system() {
return system; PlanSystem mockSystem = Mockito.mock(PlanSystem.class);
when(mockSystem.getPlanFiles()).thenReturn(component.files());
return mockSystem;
} }
} }

View File

@ -17,7 +17,10 @@
package com.djrapitops.plan.storage.database; package com.djrapitops.plan.storage.database;
import com.djrapitops.plan.PlanSystem; import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.delivery.DeliveryUtilities;
import com.djrapitops.plan.identification.Server; 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.queries.*;
import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction; import com.djrapitops.plan.storage.database.transactions.StoreServerInformationTransaction;
import com.djrapitops.plan.storage.database.transactions.commands.RemoveEverythingTransaction; 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.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import utilities.DBPreparer; import utilities.DBPreparer;
import utilities.RandomData; import utilities.RandomData;
import utilities.mocks.PluginMockComponent;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.UUID; import java.util.UUID;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
/** /**
* Tests for SQLite Database. * 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 final int TEST_PORT_NUMBER = RandomData.randomInt(9005, 9500);
private static PlanSystem system;
private static Database database; private static Database database;
private static DatabaseTestComponent component;
@BeforeAll @BeforeAll
static void setupDatabase(@TempDir Path temp) throws Exception { static void setupDatabase(@TempDir Path temp) throws Exception {
system = new PluginMockComponent(temp).getPlanSystem(); component = DaggerDatabaseTestComponent.builder()
database = new DBPreparer(system, TEST_PORT_NUMBER).prepareSQLite() .bindTemporaryDirectory(temp)
.build();
component.enable();
database = new DBPreparer(component, TEST_PORT_NUMBER).prepareSQLite()
.orElseThrow(IllegalStateException::new); .orElseThrow(IllegalStateException::new);
} }
@ -98,7 +105,7 @@ public class SQLiteTest implements DatabaseTest,
@AfterAll @AfterAll
static void disableSystem() { static void disableSystem() {
if (database != null) database.close(); if (database != null) database.close();
system.disable(); component.disable();
} }
@Override @Override
@ -108,11 +115,33 @@ public class SQLiteTest implements DatabaseTest,
@Override @Override
public UUID serverUUID() { 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 @Override
public PlanSystem system() { public PlanSystem system() {
return system; PlanSystem mockSystem = Mockito.mock(PlanSystem.class);
when(mockSystem.getPlanFiles()).thenReturn(component.files());
return mockSystem;
} }
} }

View File

@ -76,7 +76,7 @@ public interface DatabaseBackupTest extends DatabaseTestPreparer {
default void testBackupAndRestoreSQLite() throws Exception { default void testBackupAndRestoreSQLite() throws Exception {
File tempFile = Files.createTempFile(system().getPlanFiles().getDataFolder().toPath(), "backup-", ".db").toFile(); File tempFile = Files.createTempFile(system().getPlanFiles().getDataFolder().toPath(), "backup-", ".db").toFile();
tempFile.deleteOnExit(); tempFile.deleteOnExit();
SQLiteDB backup = system().getDatabaseSystem().getSqLiteFactory().usingFile(tempFile); SQLiteDB backup = dbSystem().getSqLiteFactory().usingFile(tempFile);
backup.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService); backup.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService);
try { try {
backup.init(); backup.init();
@ -103,7 +103,7 @@ public interface DatabaseBackupTest extends DatabaseTestPreparer {
default void testBackupAndRestoreH2() throws Exception { default void testBackupAndRestoreH2() throws Exception {
File tempFile = Files.createTempFile(system().getPlanFiles().getDataFolder().toPath(), "backup-", ".db").toFile(); File tempFile = Files.createTempFile(system().getPlanFiles().getDataFolder().toPath(), "backup-", ".db").toFile();
tempFile.deleteOnExit(); tempFile.deleteOnExit();
H2DB backup = system().getDatabaseSystem().getH2Factory().usingFile(tempFile); H2DB backup = dbSystem().getH2Factory().usingFile(tempFile);
backup.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService); backup.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService);
try { try {
backup.init(); backup.init();

View File

@ -49,7 +49,7 @@ class ErrorLoggerTest {
PluginMockComponent component = new PluginMockComponent(dir); PluginMockComponent component = new PluginMockComponent(dir);
SYSTEM = component.getPlanSystem(); SYSTEM = component.getPlanSystem();
SYSTEM.enable(); SYSTEM.enable();
UNDER_TEST = SYSTEM.getErrorLogger(); UNDER_TEST = component.getPluginErrorLogger();
LOGS_DIR = SYSTEM.getPlanFiles().getLogsDirectory(); LOGS_DIR = SYSTEM.getPlanFiles().getLogsDirectory();
} }

View File

@ -34,11 +34,15 @@ import java.util.Optional;
public class DBPreparer { public class DBPreparer {
private final PlanSystem system; private final Dependencies dependencies;
private final int testPortNumber; private final int testPortNumber;
public DBPreparer(PlanSystem system, 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; this.testPortNumber = testPortNumber;
} }
@ -53,12 +57,12 @@ public class DBPreparer {
} }
private SQLDB prepareDBByName(String dbName) throws EnableException { private SQLDB prepareDBByName(String dbName) throws EnableException {
PlanConfig config = system.getConfigSystem().getConfig(); PlanConfig config = dependencies.config();
config.set(WebserverSettings.PORT, testPortNumber); config.set(WebserverSettings.PORT, testPortNumber);
config.set(DatabaseSettings.TYPE, dbName); config.set(DatabaseSettings.TYPE, dbName);
system.enable();
DBSystem dbSystem = system.getDatabaseSystem(); DBSystem dbSystem = dependencies.dbSystem();
dbSystem.enable();
SQLDB db = (SQLDB) dbSystem.getActiveDatabaseByName(dbName); SQLDB db = (SQLDB) dbSystem.getActiveDatabaseByName(dbName);
db.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService); db.setTransactionExecutorServiceProvider(MoreExecutors::newDirectExecutorService);
db.init(); db.init();
@ -91,7 +95,7 @@ public class DBPreparer {
} }
public Optional<Database> prepareMySQL() throws EnableException { public Optional<Database> prepareMySQL() throws EnableException {
PlanConfig config = system.getConfigSystem().getConfig(); PlanConfig config = dependencies.config();
Optional<String> formattedDB = setUpMySQLSettings(config); Optional<String> formattedDB = setUpMySQLSettings(config);
if (formattedDB.isPresent()) { if (formattedDB.isPresent()) {
String formattedDatabase = formattedDB.get(); String formattedDatabase = formattedDB.get();
@ -108,4 +112,29 @@ public class DBPreparer {
} }
return Optional.empty(); 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();
}
}
} }

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
};
}
}

View File

@ -19,13 +19,14 @@ package utilities.dagger;
import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.PlanSystem; import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.commands.PlanCommand; import com.djrapitops.plan.commands.PlanCommand;
import com.djrapitops.plan.modules.APFModule;
import com.djrapitops.plan.modules.PlaceholderModule; import com.djrapitops.plan.modules.PlaceholderModule;
import com.djrapitops.plan.modules.SystemObjectProvidingModule; import com.djrapitops.plan.utilities.logging.PluginErrorLogger;
import dagger.BindsInstance; import dagger.BindsInstance;
import dagger.Component; import dagger.Component;
import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import java.nio.file.Path;
/** /**
* Dagger component for {@link com.djrapitops.plan.PlanPlugin} based Plan system. * Dagger component for {@link com.djrapitops.plan.PlanPlugin} based Plan system.
@ -35,20 +36,25 @@ import javax.inject.Singleton;
@Singleton @Singleton
@Component(modules = { @Component(modules = {
PlanPluginModule.class, PlanPluginModule.class,
SystemObjectProvidingModule.class, TestSystemObjectProvidingModule.class,
APFModule.class, TestAPFModule.class,
PlaceholderModule.class, PlaceholderModule.class,
PluginServerPropertiesModule.class, PluginServerPropertiesModule.class,
PluginSuperClassBindingModule.class PluginSuperClassBindingModule.class,
DBSystemModule.class
}) })
public interface PlanPluginComponent { public interface PlanPluginComponent {
PlanCommand planCommand(); PlanCommand planCommand();
PlanSystem system(); PlanSystem system();
PluginErrorLogger pluginErrorLogger();
@Component.Builder @Component.Builder
interface Builder { interface Builder {
@BindsInstance
Builder bindTemporaryDirectory(@Named("tempDir") Path tempDir);
@BindsInstance @BindsInstance
Builder plan(PlanPlugin plan); Builder plan(PlanPlugin plan);

View File

@ -18,18 +18,9 @@ package utilities.dagger;
import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.TaskSystem; import com.djrapitops.plan.TaskSystem;
import com.djrapitops.plan.exceptions.EnableException;
import com.djrapitops.plan.gathering.ServerSensor; import com.djrapitops.plan.gathering.ServerSensor;
import com.djrapitops.plan.gathering.listeners.ListenerSystem; import com.djrapitops.plan.gathering.listeners.ListenerSystem;
import com.djrapitops.plan.processing.Processing; 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 com.djrapitops.plugin.task.RunnableFactory;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
@ -49,29 +40,6 @@ import static org.mockito.Mockito.when;
@Module @Module
public class PluginSuperClassBindingModule { 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 @Provides
@Singleton @Singleton
TaskSystem provideTaskSystem(RunnableFactory runnableFactory) { TaskSystem provideTaskSystem(RunnableFactory runnableFactory) {

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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<String> 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);
};
}
}

View File

@ -18,6 +18,7 @@ package utilities.mocks;
import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.PlanPlugin;
import com.djrapitops.plan.PlanSystem; import com.djrapitops.plan.PlanSystem;
import com.djrapitops.plan.utilities.logging.PluginErrorLogger;
import utilities.dagger.DaggerPlanPluginComponent; import utilities.dagger.DaggerPlanPluginComponent;
import utilities.dagger.PlanPluginComponent; import utilities.dagger.PlanPluginComponent;
@ -50,9 +51,20 @@ public class PluginMockComponent {
} }
public PlanSystem getPlanSystem() throws Exception { public PlanSystem getPlanSystem() throws Exception {
if (component == null) { initComponent();
component = DaggerPlanPluginComponent.builder().plan(getPlanMock()).build();
}
return component.system(); 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();
}
} }

View File

@ -50,7 +50,10 @@ public class NukkitAFKListener implements Listener {
private final ErrorLogger errorLogger; private final ErrorLogger errorLogger;
@Inject @Inject
public NukkitAFKListener(PlanConfig config, ErrorLogger errorLogger) { public NukkitAFKListener(
PlanConfig config,
ErrorLogger errorLogger
) {
this.errorLogger = errorLogger; this.errorLogger = errorLogger;
this.ignorePermissionInfo = new HashMap<>(); this.ignorePermissionInfo = new HashMap<>();