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 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;

View File

@ -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;

View File

@ -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;
}

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.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;
}
}

View File

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

View File

@ -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> 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) {
public interface ErrorLogger extends ErrorHandler {
default <T extends ExceptionWithContext> 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<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);
}
}
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<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;
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();

View File

@ -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");

View File

@ -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<String>(testSQL) {
@Override
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;
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

View File

@ -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;
}
}

View File

@ -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<Database> mysql = new DBPreparer(system, TEST_PORT_NUMBER).prepareMySQL();
component = DaggerDatabaseTestComponent.builder()
.bindTemporaryDirectory(temp)
.build();
component.enable();
Optional<Database> 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;
}
}

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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();
}

View File

@ -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<Database> prepareMySQL() throws EnableException {
PlanConfig config = system.getConfigSystem().getConfig();
PlanConfig config = dependencies.config();
Optional<String> 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();
}
}
}

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.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);

View File

@ -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) {

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.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();
}
}

View File

@ -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<>();