diff --git a/README.md b/README.md index d77915765..efd204a9a 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ To learn more about configuration, usage and features of BanManager, take a look at [the website](https://banmanagement.com/docs/banmanager/configuration) or view [the website demo](https://demo.banmanagement.com). ## Requirements -- Java 8+ (JDK21+ required to build from source) +- Java 17+ (JDK21+ required to build from source) - CraftBukkit/Spigot/Paper, BungeeCord or Sponge for Minecraft 1.7.2+ - Optionally [MySQL or MariaDB](https://banmanagement.com/docs/banmanager/install#setup-shared-database-optional) diff --git a/buildSrc/src/main/kotlin/CommonConfig.kt b/buildSrc/src/main/kotlin/CommonConfig.kt index e8f5ab4c2..1c8b9b146 100644 --- a/buildSrc/src/main/kotlin/CommonConfig.kt +++ b/buildSrc/src/main/kotlin/CommonConfig.kt @@ -14,11 +14,11 @@ fun Project.applyCommonConfiguration() { } dependencies { - "compileOnly"("org.projectlombok:lombok:1.18.36") - "annotationProcessor"("org.projectlombok:lombok:1.18.36") + "compileOnly"("org.projectlombok:lombok:1.18.38") + "annotationProcessor"("org.projectlombok:lombok:1.18.38") - "testCompileOnly"("org.projectlombok:lombok:1.18.36") - "testAnnotationProcessor"("org.projectlombok:lombok:1.18.36") + "testCompileOnly"("org.projectlombok:lombok:1.18.38") + "testAnnotationProcessor"("org.projectlombok:lombok:1.18.38") } configurations.all { diff --git a/buildSrc/src/main/kotlin/PlatformConfig.kt b/buildSrc/src/main/kotlin/PlatformConfig.kt index 03da6c0dd..e4ebb0554 100644 --- a/buildSrc/src/main/kotlin/PlatformConfig.kt +++ b/buildSrc/src/main/kotlin/PlatformConfig.kt @@ -2,18 +2,12 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import com.github.jengelman.gradle.plugins.shadow.ShadowExtension import org.gradle.api.Project import org.gradle.api.plugins.JavaPluginExtension -import org.gradle.api.plugins.quality.CheckstyleExtension -import org.gradle.api.publish.PublishingExtension -import org.gradle.api.publish.maven.MavenPublication import org.gradle.api.tasks.javadoc.Javadoc -import org.gradle.api.tasks.testing.Test import org.gradle.external.javadoc.StandardJavadocDocletOptions import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.dependencies -import org.gradle.kotlin.dsl.get import org.gradle.kotlin.dsl.named -import org.gradle.kotlin.dsl.register import org.gradle.kotlin.dsl.withType import org.gradle.kotlin.dsl.the @@ -34,7 +28,7 @@ fun Project.applyPlatformAndCoreConfiguration() { ext["internalVersion"] = internalVersion - // Java 8 turns on doclint which we fail + // Suppress doclint to keep javadoc builds green; tags below document supported custom tags. tasks.withType().configureEach { (options as StandardJavadocDocletOptions).apply { addStringOption("Xdoclint:none", "-quiet") diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 3a969842c..f8117ced9 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,5 +1,3 @@ object Versions { - const val JUNIT = "4.13" - const val MOCKITO = "3.7.7" const val ADVENTURE = "4.21.0" } diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index c494940b0..ad83bdd25 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -83,9 +83,9 @@ dependencies { "compileOnly"("net.kyori:adventure-api:${Versions.ADVENTURE}") "compileOnly"("net.kyori:adventure-text-serializer-gson:${Versions.ADVENTURE}") "compileOnly"("net.kyori:adventure-text-serializer-json:${Versions.ADVENTURE}") - "compileOnly"("me.clip:placeholderapi:2.10.9") - "shadeOnly"("org.bstats:bstats-bukkit:2.2.1") - "shadeOnly"("org.slf4j:slf4j-api:1.7.36") + "compileOnly"("me.clip:placeholderapi:2.12.2") + "shadeOnly"("org.bstats:bstats-bukkit:3.2.1") + "shadeOnly"("org.slf4j:slf4j-api:2.0.17") } tasks.named("processResources") { @@ -119,15 +119,23 @@ tasks.named("shadowJar") { include(dependency("org.bstats:.*:.*")) include(dependency("org.slf4j:.*:.*")) - - relocate("org.bstats", "me.confuser.banmanager.common.bstats") - relocate("org.slf4j", "me.confuser.banmanager.common.slf4j") } + // Relocate at task level so resource paths and service file contents are + // also rewritten (the SLF4J 2.x ServiceLoader needs the META-INF/services + // entry to be relocated to the shaded package). + relocate("org.bstats", "me.confuser.banmanager.common.bstats") + relocate("org.slf4j", "me.confuser.banmanager.common.slf4j") + + // Required for SLF4J 2.x service discovery: merges + relocates the + // META-INF/services/org.slf4j.spi.SLF4JServiceProvider entry. + mergeServiceFiles() + exclude("GradleStart**") exclude(".cache"); exclude("LICENSE*") - exclude("META-INF/services/**") + // Keep META-INF/services so the relocated SLF4J 2.x ServiceLoader can find + // BanManagerSlf4jServiceProvider; shaded deps here ship no service files. exclude("META-INF/maven/**") exclude("org/intellij/**") exclude("org/jetbrains/**") @@ -137,6 +145,15 @@ tasks.named("shadowJar") { minimize { exclude(dependency("org.bstats:.*:.*")) exclude(dependency("org.slf4j:.*:.*")) + // JDBC drivers, HikariCP and ORMLite load codecs / dialects / drivers + // via ServiceLoader. Static analysis can't see those references, so + // exclude them from minimisation to avoid stripping classes that are + // listed in the merged META-INF/services entries. + exclude(dependency("org.mariadb.jdbc:mariadb-java-client:.*")) + exclude(dependency("com.mysql:mysql-connector-j:.*")) + exclude(dependency("com.zaxxer:HikariCP:.*")) + exclude(dependency("com.j256.ormlite:.*:.*")) + exclude(dependency("com.h2database:.*:.*")) } } diff --git a/bukkit/src/main/java/me/confuser/banmanager/bukkit/listeners/WebhookListener.java b/bukkit/src/main/java/me/confuser/banmanager/bukkit/listeners/WebhookListener.java index b0872accd..7263ba555 100644 --- a/bukkit/src/main/java/me/confuser/banmanager/bukkit/listeners/WebhookListener.java +++ b/bukkit/src/main/java/me/confuser/banmanager/bukkit/listeners/WebhookListener.java @@ -3,7 +3,7 @@ import me.confuser.banmanager.bukkit.api.events.*; import me.confuser.banmanager.common.BanManagerPlugin; import me.confuser.banmanager.common.listeners.CommonWebhookListener; -import me.confuser.banmanager.common.listeners.CommonWebhookListener.WebhookData; +import me.confuser.banmanager.common.data.Webhook; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -19,62 +19,62 @@ public WebhookListener(BanManagerPlugin plugin) { @EventHandler(priority = EventPriority.MONITOR) public void notifyOnBan(PlayerBannedEvent event) { - List webhooks = listener.notifyOnBan(event.getBan()); + List webhooks = listener.notifyOnBan(event.getBan()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.MONITOR) public void notifyOnMute(PlayerMutedEvent event) { - List webhooks = listener.notifyOnMute(event.getMute()); + List webhooks = listener.notifyOnMute(event.getMute()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.MONITOR) public void notifyOnBan(IpBannedEvent event) { - List webhooks = listener.notifyOnBan(event.getBan()); + List webhooks = listener.notifyOnBan(event.getBan()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.MONITOR) public void notifyOnKick(PlayerKickedEvent event) { - List webhooks = listener.notifyOnKick(event.getKick()); + List webhooks = listener.notifyOnKick(event.getKick()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.MONITOR) public void notifyOnWarn(PlayerWarnedEvent event) { - List webhooks = listener.notifyOnWarn(event.getWarning()); + List webhooks = listener.notifyOnWarn(event.getWarning()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.MONITOR) public void notifyOnUnban(PlayerUnbanEvent event) { - List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); + List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.MONITOR) public void notifyOnUnban(IpUnbanEvent event) { - List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); + List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.MONITOR) public void notifyOnUnmute(PlayerUnmuteEvent event) { - List webhooks = listener.notifyOnUnmute(event.getMute(), event.getActor(), event.getReason()); + List webhooks = listener.notifyOnUnmute(event.getMute(), event.getActor(), event.getReason()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.MONITOR) public void notifyOnReport(PlayerReportedEvent event) { - List webhooks = listener.notifyOnReport(event.getReport(), event.getReport().getActor(), event.getReport().getReason()); + List webhooks = listener.notifyOnReport(event.getReport(), event.getReport().getActor(), event.getReport().getReason()); sendAll(webhooks, event.isSilent()); } - private void sendAll(List webhooks, boolean isSilent) { - for (WebhookData data : webhooks) { - if (isSilent && data.ignoreSilent) continue; - if (data.url == null || data.payload == null || data.url.isEmpty() || data.payload.isEmpty()) continue; + private void sendAll(List webhooks, boolean isSilent) { + for (Webhook data : webhooks) { + if (isSilent && data.ignoreSilent()) continue; + if (data.url() == null || data.payload() == null || data.url().isEmpty() || data.payload().isEmpty()) continue; listener.sendAsync(data); } } diff --git a/bukkit/src/main/java/org/slf4j/impl/BanManagerSlf4jLogger.java b/bukkit/src/main/java/org/slf4j/impl/BanManagerSlf4jLogger.java index 10dc7dead..371487b49 100644 --- a/bukkit/src/main/java/org/slf4j/impl/BanManagerSlf4jLogger.java +++ b/bukkit/src/main/java/org/slf4j/impl/BanManagerSlf4jLogger.java @@ -2,18 +2,19 @@ import me.confuser.banmanager.common.BanManagerPlugin; import me.confuser.banmanager.common.CommonLogger; -import org.slf4j.helpers.FormattingTuple; -import org.slf4j.helpers.MarkerIgnoringBase; +import org.slf4j.Marker; +import org.slf4j.event.Level; +import org.slf4j.helpers.LegacyAbstractLogger; import org.slf4j.helpers.MessageFormatter; /** - * SLF4J logger that delegates to BanManager's {@link CommonLogger}. + * SLF4J 2.x logger that delegates to BanManager's {@link CommonLogger}. * *

Level filtering: when debug mode is off, TRACE / DEBUG / INFO are * suppressed. This replaces the old {@code disableDatabaseLogging()} system * property which has no effect when ORMLite uses SLF4J instead of LocalLog.

*/ -public class BanManagerSlf4jLogger extends MarkerIgnoringBase { +public class BanManagerSlf4jLogger extends LegacyAbstractLogger { private static final long serialVersionUID = 1L; @@ -31,8 +32,6 @@ private boolean isDebugMode() { return plugin != null && plugin.getConfig() != null && plugin.getConfig().isDebugEnabled(); } - // --- Level checks ----------------------------------------------------------- - @Override public boolean isTraceEnabled() { return isDebugMode(); @@ -58,178 +57,44 @@ public boolean isErrorEnabled() { return true; } - // --- TRACE ------------------------------------------------------------------ - - @Override - public void trace(String msg) { - if (!isTraceEnabled()) return; - CommonLogger l = logger(); - if (l != null) l.info("[TRACE] " + msg); - } - - @Override - public void trace(String format, Object arg) { - if (!isTraceEnabled()) return; - FormattingTuple ft = MessageFormatter.format(format, arg); - trace(ft.getMessage()); - } - - @Override - public void trace(String format, Object arg1, Object arg2) { - if (!isTraceEnabled()) return; - FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); - trace(ft.getMessage()); - } - - @Override - public void trace(String format, Object... arguments) { - if (!isTraceEnabled()) return; - FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); - trace(ft.getMessage()); - } - - @Override - public void trace(String msg, Throwable t) { - if (!isTraceEnabled()) return; - CommonLogger l = logger(); - if (l != null) l.warning("[TRACE] " + msg, t); - } - - // --- DEBUG ------------------------------------------------------------------ - - @Override - public void debug(String msg) { - if (!isDebugEnabled()) return; - CommonLogger l = logger(); - if (l != null) l.info("[DEBUG] " + msg); - } - - @Override - public void debug(String format, Object arg) { - if (!isDebugEnabled()) return; - FormattingTuple ft = MessageFormatter.format(format, arg); - debug(ft.getMessage()); - } - - @Override - public void debug(String format, Object arg1, Object arg2) { - if (!isDebugEnabled()) return; - FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); - debug(ft.getMessage()); - } - - @Override - public void debug(String format, Object... arguments) { - if (!isDebugEnabled()) return; - FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); - debug(ft.getMessage()); - } - - @Override - public void debug(String msg, Throwable t) { - if (!isDebugEnabled()) return; - CommonLogger l = logger(); - if (l != null) l.warning("[DEBUG] " + msg, t); - } - - // --- INFO ------------------------------------------------------------------- - - @Override - public void info(String msg) { - if (!isInfoEnabled()) return; - CommonLogger l = logger(); - if (l != null) l.info(msg); - } - - @Override - public void info(String format, Object arg) { - if (!isInfoEnabled()) return; - FormattingTuple ft = MessageFormatter.format(format, arg); - info(ft.getMessage()); - } - - @Override - public void info(String format, Object arg1, Object arg2) { - if (!isInfoEnabled()) return; - FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); - info(ft.getMessage()); - } - - @Override - public void info(String format, Object... arguments) { - if (!isInfoEnabled()) return; - FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); - info(ft.getMessage()); - } - - @Override - public void info(String msg, Throwable t) { - if (!isInfoEnabled()) return; - CommonLogger l = logger(); - if (l != null) l.warning(msg, t); - } - - // --- WARN ------------------------------------------------------------------- - - @Override - public void warn(String msg) { - CommonLogger l = logger(); - if (l != null) l.warning(msg); - } - - @Override - public void warn(String format, Object arg) { - FormattingTuple ft = MessageFormatter.format(format, arg); - warn(ft.getMessage()); - } - - @Override - public void warn(String format, Object arg1, Object arg2) { - FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); - warn(ft.getMessage()); - } - - @Override - public void warn(String format, Object... arguments) { - FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); - warn(ft.getMessage()); - } - - @Override - public void warn(String msg, Throwable t) { - CommonLogger l = logger(); - if (l != null) l.warning(msg, t); - } - - // --- ERROR ------------------------------------------------------------------ - - @Override - public void error(String msg) { - CommonLogger l = logger(); - if (l != null) l.severe(msg); - } - - @Override - public void error(String format, Object arg) { - FormattingTuple ft = MessageFormatter.format(format, arg); - error(ft.getMessage()); - } - - @Override - public void error(String format, Object arg1, Object arg2) { - FormattingTuple ft = MessageFormatter.format(format, arg1, arg2); - error(ft.getMessage()); - } - @Override - public void error(String format, Object... arguments) { - FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments); - error(ft.getMessage()); + protected String getFullyQualifiedCallerName() { + return null; } @Override - public void error(String msg, Throwable t) { + protected void handleNormalizedLoggingCall(Level level, + Marker marker, + String messagePattern, + Object[] arguments, + Throwable throwable) { CommonLogger l = logger(); - if (l != null) l.severe(msg, t); + if (l == null) return; + + String formatted = (arguments == null || arguments.length == 0) + ? messagePattern + : MessageFormatter.arrayFormat(messagePattern, arguments).getMessage(); + + String prefix = switch (level) { + case TRACE -> "[TRACE] "; + case DEBUG -> "[DEBUG] "; + default -> ""; + }; + String message = prefix + formatted; + + switch (level) { + case TRACE, DEBUG, INFO -> { + if (throwable == null) l.info(message); + else l.warning(message, throwable); + } + case WARN -> { + if (throwable == null) l.warning(message); + else l.warning(message, throwable); + } + case ERROR -> { + if (throwable == null) l.severe(message); + else l.severe(message, throwable); + } + } } } diff --git a/bukkit/src/main/java/org/slf4j/impl/BanManagerSlf4jServiceProvider.java b/bukkit/src/main/java/org/slf4j/impl/BanManagerSlf4jServiceProvider.java new file mode 100644 index 000000000..6e7978379 --- /dev/null +++ b/bukkit/src/main/java/org/slf4j/impl/BanManagerSlf4jServiceProvider.java @@ -0,0 +1,53 @@ +package org.slf4j.impl; + +import org.slf4j.ILoggerFactory; +import org.slf4j.IMarkerFactory; +import org.slf4j.helpers.BasicMDCAdapter; +import org.slf4j.helpers.BasicMarkerFactory; +import org.slf4j.spi.MDCAdapter; +import org.slf4j.spi.SLF4JServiceProvider; + +/** + * SLF4J 2.x service provider that wires {@link BanManagerLoggerFactory} into + * the SLF4J API. Discovered via {@code META-INF/services/org.slf4j.spi.SLF4JServiceProvider} + * (also relocated alongside the rest of {@code org.slf4j} so the shaded + * HikariCP / ORMLite pick it up automatically). + */ +public class BanManagerSlf4jServiceProvider implements SLF4JServiceProvider { + + // Track the SLF4J API version this provider was compiled against. Must be + // updated when bumping the slf4j-api dependency to keep the version-mismatch + // warning accurate. + public static final String REQUESTED_API_VERSION = "2.0.99"; + + private ILoggerFactory loggerFactory; + private IMarkerFactory markerFactory; + private MDCAdapter mdcAdapter; + + @Override + public void initialize() { + loggerFactory = new BanManagerLoggerFactory(); + markerFactory = new BasicMarkerFactory(); + mdcAdapter = new BasicMDCAdapter(); + } + + @Override + public ILoggerFactory getLoggerFactory() { + return loggerFactory; + } + + @Override + public IMarkerFactory getMarkerFactory() { + return markerFactory; + } + + @Override + public MDCAdapter getMDCAdapter() { + return mdcAdapter; + } + + @Override + public String getRequestedApiVersion() { + return REQUESTED_API_VERSION; + } +} diff --git a/bukkit/src/main/java/org/slf4j/impl/StaticLoggerBinder.java b/bukkit/src/main/java/org/slf4j/impl/StaticLoggerBinder.java deleted file mode 100644 index 6692c58bc..000000000 --- a/bukkit/src/main/java/org/slf4j/impl/StaticLoggerBinder.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.slf4j.impl; - -import org.slf4j.ILoggerFactory; -import org.slf4j.spi.LoggerFactoryBinder; - -/** - * SLF4J 1.7.x binding entry point. Shadow relocates this alongside the rest of - * org.slf4j so the shaded HikariCP / ORMLite pick it up automatically. - * - *

If ever upgrading to SLF4J 2.x, this class must be replaced with a - * {@code SLF4JServiceProvider} registered via {@code META-INF/services}.

- */ -public class StaticLoggerBinder implements LoggerFactoryBinder { - - private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder(); - - // Must NOT be final so the compiler doesn't inline it. - public static String REQUESTED_API_VERSION = "1.6.99"; - - private final ILoggerFactory loggerFactory; - - private StaticLoggerBinder() { - loggerFactory = new BanManagerLoggerFactory(); - } - - public static StaticLoggerBinder getSingleton() { - return SINGLETON; - } - - @Override - public ILoggerFactory getLoggerFactory() { - return loggerFactory; - } - - @Override - public String getLoggerFactoryClassStr() { - return BanManagerLoggerFactory.class.getName(); - } -} diff --git a/bukkit/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/bukkit/src/main/java/org/slf4j/impl/StaticMDCBinder.java deleted file mode 100644 index b3e9d9b06..000000000 --- a/bukkit/src/main/java/org/slf4j/impl/StaticMDCBinder.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.slf4j.impl; - -import org.slf4j.helpers.NOPMDCAdapter; -import org.slf4j.spi.MDCAdapter; - -public class StaticMDCBinder { - - public static final StaticMDCBinder SINGLETON = new StaticMDCBinder(); - - public static StaticMDCBinder getSingleton() { - return SINGLETON; - } - - public MDCAdapter getMDCA() { - return new NOPMDCAdapter(); - } - - public String getMDCAdapterClassStr() { - return NOPMDCAdapter.class.getName(); - } -} diff --git a/bukkit/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/bukkit/src/main/java/org/slf4j/impl/StaticMarkerBinder.java deleted file mode 100644 index 6f6ee4c3f..000000000 --- a/bukkit/src/main/java/org/slf4j/impl/StaticMarkerBinder.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.slf4j.impl; - -import org.slf4j.IMarkerFactory; -import org.slf4j.helpers.BasicMarkerFactory; -import org.slf4j.spi.MarkerFactoryBinder; - -public class StaticMarkerBinder implements MarkerFactoryBinder { - - public static final StaticMarkerBinder SINGLETON = new StaticMarkerBinder(); - - private final IMarkerFactory markerFactory = new BasicMarkerFactory(); - - public static StaticMarkerBinder getSingleton() { - return SINGLETON; - } - - @Override - public IMarkerFactory getMarkerFactory() { - return markerFactory; - } - - @Override - public String getMarkerFactoryClassStr() { - return BasicMarkerFactory.class.getName(); - } -} diff --git a/bungee/build.gradle.kts b/bungee/build.gradle.kts index 2789c0391..22c174db2 100644 --- a/bungee/build.gradle.kts +++ b/bungee/build.gradle.kts @@ -64,7 +64,7 @@ configurations { dependencies { api(project(":BanManagerCommon")) compileOnly("net.md-5:bungeecord-api:1.21-R0.4") - "shadeOnly"("org.bstats:bstats-bungeecord:2.2.1") + "shadeOnly"("org.bstats:bstats-bungeecord:3.2.1") } tasks.named("processResources") { @@ -99,17 +99,24 @@ tasks.named("shadowJar") { relocate("org.bstats", "me.confuser.banmanager.common.bstats") } + + mergeServiceFiles() + exclude("GradleStart**") exclude(".cache"); exclude("LICENSE*") - exclude("META-INF/services/**") exclude("META-INF/maven/**") + // BanManagerSlf4jServiceProvider only ships in (and is relocated by) Bukkit. + // BungeeCord provides its own SLF4J 2.x implementation, so removing the + // bundled provider entry avoids a ServiceConfigurationError at startup. + exclude("META-INF/services/org.slf4j.spi.SLF4JServiceProvider") exclude("org/intellij/**") exclude("org/jetbrains/**") exclude("velocity.yml") minimize { exclude(dependency("org.bstats:.*:.*")) + exclude(dependency(":BanManagerLibs")) } } diff --git a/bungee/src/main/java/me/confuser/banmanager/bungee/listeners/WebhookListener.java b/bungee/src/main/java/me/confuser/banmanager/bungee/listeners/WebhookListener.java index 7d34a0b59..a58c3fee8 100644 --- a/bungee/src/main/java/me/confuser/banmanager/bungee/listeners/WebhookListener.java +++ b/bungee/src/main/java/me/confuser/banmanager/bungee/listeners/WebhookListener.java @@ -3,7 +3,7 @@ import me.confuser.banmanager.bungee.api.events.*; import me.confuser.banmanager.common.BanManagerPlugin; import me.confuser.banmanager.common.listeners.CommonWebhookListener; -import me.confuser.banmanager.common.listeners.CommonWebhookListener.WebhookData; +import me.confuser.banmanager.common.data.Webhook; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.event.EventPriority; @@ -19,62 +19,62 @@ public WebhookListener(BanManagerPlugin plugin) { @EventHandler(priority = EventPriority.HIGHEST) public void notifyOnBan(PlayerBannedEvent event) { - List webhooks = listener.notifyOnBan(event.getBan()); + List webhooks = listener.notifyOnBan(event.getBan()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.HIGHEST) public void notifyOnMute(PlayerMutedEvent event) { - List webhooks = listener.notifyOnMute(event.getMute()); + List webhooks = listener.notifyOnMute(event.getMute()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.HIGHEST) public void notifyOnBan(IpBannedEvent event) { - List webhooks = listener.notifyOnBan(event.getBan()); + List webhooks = listener.notifyOnBan(event.getBan()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.HIGHEST) public void notifyOnKick(PlayerKickedEvent event) { - List webhooks = listener.notifyOnKick(event.getKick()); + List webhooks = listener.notifyOnKick(event.getKick()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.HIGHEST) public void notifyOnWarn(PlayerWarnedEvent event) { - List webhooks = listener.notifyOnWarn(event.getWarning()); + List webhooks = listener.notifyOnWarn(event.getWarning()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.HIGHEST) public void notifyOnUnban(PlayerUnbanEvent event) { - List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); + List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.HIGHEST) public void notifyOnUnban(IpUnbanEvent event) { - List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); + List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.HIGHEST) public void notifyOnUnmute(PlayerUnmuteEvent event) { - List webhooks = listener.notifyOnUnmute(event.getMute(), event.getActor(), event.getReason()); + List webhooks = listener.notifyOnUnmute(event.getMute(), event.getActor(), event.getReason()); sendAll(webhooks, event.isSilent()); } @EventHandler(priority = EventPriority.HIGHEST) public void notifyOnReport(PlayerReportedEvent event) { - List webhooks = listener.notifyOnReport(event.getReport(), event.getReport().getActor(), event.getReport().getReason()); + List webhooks = listener.notifyOnReport(event.getReport(), event.getReport().getActor(), event.getReport().getReason()); sendAll(webhooks, event.isSilent()); } - private void sendAll(List webhooks, boolean isSilent) { - for (WebhookData data : webhooks) { - if (isSilent && data.ignoreSilent) continue; - if (data.url == null || data.payload == null || data.url.isEmpty() || data.payload.isEmpty()) continue; + private void sendAll(List webhooks, boolean isSilent) { + for (Webhook data : webhooks) { + if (isSilent && data.ignoreSilent()) continue; + if (data.url() == null || data.payload() == null || data.url().isEmpty() || data.payload().isEmpty()) continue; listener.sendAsync(data); } } diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 0a9943bb7..6e2944a7b 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -48,24 +48,28 @@ mavenPublishing { dependencies { api(project(":BanManagerLibs")) - testImplementation("junit:junit:4.13") - testImplementation("org.hamcrest:hamcrest-library:1.2.1") - testImplementation("org.powermock:powermock-module-junit4:2.0.2") - testImplementation("org.powermock:powermock-api-mockito2:2.0.2") - testImplementation("com.github.javafaker:javafaker:1.0.2") - testImplementation("org.awaitility:awaitility:4.0.1") - testImplementation("ch.vorburger.mariaDB4j:mariaDB4j:2.6.0") + testImplementation(platform("org.junit:junit-bom:5.11.4")) + testImplementation("org.junit.jupiter:junit-jupiter") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") + testImplementation("org.hamcrest:hamcrest:2.2") + testImplementation("org.mockito:mockito-core:5.14.2") + testImplementation("net.datafaker:datafaker:2.5.4") + testImplementation("org.awaitility:awaitility:4.3.0") + testImplementation("ch.vorburger.mariaDB4j:mariaDB4j:3.3.1") } tasks.withType().configureEach { - useJUnit() + useJUnitPlatform() maxHeapSize = "512m" - forkEvery = 1 // Fork a new JVM for each test class to prevent memory accumulation + // Fork a new JVM per test class. Several tests (storage, configs, MariaDB4j) leak + // static state - native handles, jdbc drivers, daemon executors - that hangs the + // suite if a single JVM keeps accumulating fixtures. Slower, but reliable. + forkEvery = 1 finalizedBy(tasks.jacocoTestReport) } jacoco { - toolVersion = "0.8.11" + toolVersion = "0.8.12" } tasks.jacocoTestReport { diff --git a/common/src/main/java/me/confuser/banmanager/common/BanManagerPlugin.java b/common/src/main/java/me/confuser/banmanager/common/BanManagerPlugin.java index b0fa85e7c..03dfdc778 100644 --- a/common/src/main/java/me/confuser/banmanager/common/BanManagerPlugin.java +++ b/common/src/main/java/me/confuser/banmanager/common/BanManagerPlugin.java @@ -9,9 +9,10 @@ import me.confuser.banmanager.common.hikari.HikariDataSource; import me.confuser.banmanager.common.ormlite.dao.GenericRawResults; import me.confuser.banmanager.common.ormlite.db.DatabaseType; -import me.confuser.banmanager.common.ormlite.db.H2DatabaseType; import me.confuser.banmanager.common.ormlite.jdbc.DataSourceConnectionSource; -import me.confuser.banmanager.common.ormlite.logger.LocalLog; +import me.confuser.banmanager.common.ormlite.jdbc.db.H2DatabaseType; +import me.confuser.banmanager.common.ormlite.logger.Level; +import me.confuser.banmanager.common.ormlite.logger.Logger; import me.confuser.banmanager.common.ormlite.support.ConnectionSource; import me.confuser.banmanager.common.ormlite.support.DatabaseConnection; import me.confuser.banmanager.common.configuration.file.YamlConfiguration; @@ -27,9 +28,15 @@ import me.confuser.banmanager.common.util.MessageRenderer; import java.io.*; +import java.net.http.HttpClient; import java.nio.file.Files; import java.sql.SQLException; +import java.time.Duration; import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import static java.lang.Long.parseLong; @@ -185,6 +192,14 @@ public class BanManagerPlugin { @Getter private MessageRegistry messageRegistry; + // Shared HTTP infrastructure for webhooks, UUID lookups and GeoIP downloads. + // Lazily initialised on first use so unit tests that don't touch HTTP avoid + // spinning up the executor. volatile ensures the double-checked locking in + // getHttpClient() publishes a fully-constructed HttpClient to other threads. + private volatile HttpClient httpClient; + private volatile ExecutorService httpExecutor; + private final Object httpLock = new Object(); + public BanManagerPlugin(PluginInfo pluginInfo, CommonLogger logger, File dataFolder, CommonScheduler scheduler, CommonServer server, CommonMetrics metrics) { this.pluginInfo = pluginInfo; this.logger = logger; @@ -297,6 +312,56 @@ public final void disable() { if (globalConn != null) { globalConn.closeQuietly(); } + + shutdownHttpExecutor(); + } + + /** + * Returns the shared {@link HttpClient}, creating it on first use. Callers + * (webhooks, UUID lookups, GeoIP downloads) share a single dedicated thread + * pool so webhook bursts do not starve the common ForkJoinPool. + * + *

Thread-safe: uses double-checked locking with a {@code volatile} field + * so concurrent callers will see a fully-constructed instance.

+ */ + public HttpClient getHttpClient() { + HttpClient existing = httpClient; + if (existing != null) return existing; + synchronized (httpLock) { + if (httpClient == null) { + AtomicInteger counter = new AtomicInteger(); + httpExecutor = Executors.newCachedThreadPool(r -> { + Thread t = new Thread(r, "BanManager-Http-" + counter.incrementAndGet()); + t.setDaemon(true); + return t; + }); + httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(10)) + .followRedirects(HttpClient.Redirect.NORMAL) + .executor(httpExecutor) + .build(); + } + return httpClient; + } + } + + private void shutdownHttpExecutor() { + ExecutorService executor; + synchronized (httpLock) { + executor = httpExecutor; + httpExecutor = null; + httpClient = null; + } + if (executor == null) return; + executor.shutdown(); + try { + if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } } public void setupConfigs() { @@ -487,11 +552,16 @@ private T reloadConfig(T newConfig, T currentConfig, String f return newConfig; } - // Only effective on platforms where ORMLite falls back to LocalLog (no SLF4J/Log4j2 - // on the classpath). On Bukkit, ORMLite auto-detects the shaded SLF4J and level - // filtering is handled by BanManagerSlf4jLogger instead. + // Silences chatty ORMLite/HikariCP TRACE/DEBUG/INFO output unless debug mode is on. + // Uses Logger.setGlobalLogLevel rather than the LOCAL_LOG_LEVEL_PROPERTY system + // property because the property name ("com.j256.simplelogging.level") is a + // hard-coded string that survives shading; setting it would also throttle any + // other plugin on the server that bundles ORMLite. setGlobalLogLevel mutates a + // static field on our shaded Logger class, so the change is isolated to BanManager. + // On Bukkit the shaded SLF4J 2.x bridge handles filtering itself, so this is a + // no-op there (Logger doesn't observe the level once an SLF4J backend is wired). private void disableDatabaseLogging() { - System.setProperty(LocalLog.LOCAL_LOG_LEVEL_PROPERTY, "WARNING"); + Logger.setGlobalLogLevel(Level.WARNING); } public boolean setupConnections() throws SQLException { @@ -572,7 +642,7 @@ public void setupStorage() throws SQLException { if (config.getLocalDb().getStorageType().equals("h2")) { try (DatabaseConnection conn = getLocalConn().getReadWriteConnection("")) { conn.executeStatement("CREATE ALIAS IF NOT EXISTS INET6_NTOA FOR \"me.confuser.banmanager.common.util.IPUtils.toString\"", DatabaseConnection.DEFAULT_RESULT_FLAGS); - } catch (IOException | SQLException e) { + } catch (Exception e) { logger.severe("An error occurred setting up H2 storage", e); } } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/CommonCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/CommonCommand.java index 2ce90c6a7..e927e48ea 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/CommonCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/CommonCommand.java @@ -44,9 +44,9 @@ public CommonCommand(BanManagerPlugin plugin, String commandName, boolean enable PluginInfo.CommandInfo info = plugin.getPluginInfo().getCommand(commandName); - this.usage = info.getUsage(); - this.permission = info.getPermission(); - this.aliases = info.getAliases(); + this.usage = info.usage(); + this.permission = info.permission(); + this.aliases = info.aliases(); this.parser = CommandParser.class; } @@ -57,9 +57,9 @@ public CommonCommand(BanManagerPlugin plugin, String commandName, boolean enable PluginInfo.CommandInfo info = pluginInfo.getCommand(commandName); - this.usage = info.getUsage(); - this.permission = info.getPermission(); - this.aliases = info.getAliases(); + this.usage = info.usage(); + this.permission = info.permission(); + this.aliases = info.aliases(); this.parser = CommandParser.class; } diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/InfoCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/InfoCommand.java index 3e3c2aeb2..e911924f9 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/InfoCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/InfoCommand.java @@ -19,7 +19,7 @@ import me.confuser.banmanager.common.util.DateUtils; import me.confuser.banmanager.common.util.IPUtils; import me.confuser.banmanager.common.util.Message; - +import me.confuser.banmanager.common.util.StorageUtils; import me.confuser.banmanager.common.util.StringUtils; import me.confuser.banmanager.common.util.parsers.InfoCommandParser; @@ -131,12 +131,12 @@ public void ipInfo(CommonSender sender, IPAddress ip, InfoCommandParser parser) for (HistoryEntry result : results) { Message message = Message.get("info.history.row") - .set("id", result.getId()) - .set("reason", result.getReason()) - .set("type", result.getType()) - .set("created", DateUtils.format(dateTimeFormat, result.getCreated())) - .set("actor", result.getActor()) - .set("meta", result.getMeta()); + .set("id", result.id()) + .set("reason", result.reason()) + .set("type", result.type()) + .set("created", DateUtils.format(dateTimeFormat, result.created())) + .set("actor", result.actor()) + .set("meta", result.meta()); messages.add(message.toString()); } @@ -390,12 +390,12 @@ public void playerInfo(CommonSender sender, String name, Integer index, InfoComm for (HistoryEntry result : results) { Message message = Message.get("info.history.row") - .set("id", result.getId()) - .set("reason", result.getReason()) - .set("type", result.getType()) - .set("created", DateUtils.format(dateTimeFormat, result.getCreated())) - .set("actor", result.getActor()) - .set("meta", result.getMeta()); + .set("id", result.id()) + .set("reason", result.reason()) + .set("type", result.type()) + .set("created", DateUtils.format(dateTimeFormat, result.created())) + .set("actor", result.actor()) + .set("meta", result.meta()); messages.add(message.toString()); } @@ -445,13 +445,13 @@ public void playerInfo(CommonSender sender, String name, Integer index, InfoComm } } } finally { - try { results.close(); } catch (IOException ignored) { } + try { results.close(); } catch (Exception ignored) { } } } finally { - try { stmt.close(); } catch (IOException ignored) { } + try { stmt.close(); } catch (Exception ignored) { } } - } catch (IOException e) { - throw new SQLException("Failed to query player stats", e); + } catch (Exception e) { + throw StorageUtils.toSqlException("Failed to query player stats", e); } messages.add(Message.get("info.stats.player") @@ -538,7 +538,7 @@ public void playerInfo(CommonSender sender, String name, Integer index, InfoComm } else { StringBuilder namesBuilder = new StringBuilder(); for (PlayerNameSummary nameData : playerNames) { - namesBuilder.append(nameData.getName()).append(", "); + namesBuilder.append(nameData.name()).append(", "); } if (namesBuilder.length() >= 2) namesBuilder.setLength(namesBuilder.length() - 2); messages.add(namesBuilder.toString()); diff --git a/common/src/main/java/me/confuser/banmanager/common/commands/NamesCommand.java b/common/src/main/java/me/confuser/banmanager/common/commands/NamesCommand.java index 92c36e977..e8a229bc7 100644 --- a/common/src/main/java/me/confuser/banmanager/common/commands/NamesCommand.java +++ b/common/src/main/java/me/confuser/banmanager/common/commands/NamesCommand.java @@ -67,9 +67,9 @@ public boolean onCommand(final CommonSender sender, CommandParser parser) { } else { for (PlayerNameSummary nameData : names) { Message.get("names.row") - .set("name", nameData.getName()) - .set("firstSeen", DateUtils.format(dateTimeFormat, nameData.getFirstSeen())) - .set("lastSeen", DateUtils.format(dateTimeFormat, nameData.getLastSeen())) + .set("name", nameData.name()) + .set("firstSeen", DateUtils.format(dateTimeFormat, nameData.firstSeen())) + .set("lastSeen", DateUtils.format(dateTimeFormat, nameData.lastSeen())) .sendTo(sender); } } @@ -90,22 +90,22 @@ static TextComponent buildNamesComponent(List names, String d for (PlayerNameSummary nameData : names) { if (hasInteractiveTemplate) { Component entry = Message.get("names.interactive") - .set("name", nameData.getName()) - .set("firstSeen", DateUtils.format(dateTimeFormat, nameData.getFirstSeen())) - .set("lastSeen", DateUtils.format(dateTimeFormat, nameData.getLastSeen())) + .set("name", nameData.name()) + .set("firstSeen", DateUtils.format(dateTimeFormat, nameData.firstSeen())) + .set("lastSeen", DateUtils.format(dateTimeFormat, nameData.lastSeen())) .resolveComponent(); message.append(entry); } else { String hoverText = Message.get("names.row") - .set("name", nameData.getName()) - .set("firstSeen", DateUtils.format(dateTimeFormat, nameData.getFirstSeen())) - .set("lastSeen", DateUtils.format(dateTimeFormat, nameData.getLastSeen())) + .set("name", nameData.name()) + .set("firstSeen", DateUtils.format(dateTimeFormat, nameData.firstSeen())) + .set("lastSeen", DateUtils.format(dateTimeFormat, nameData.lastSeen())) .toString(); message.append( - Component.text(nameData.getName()) + Component.text(nameData.name()) .color(NamedTextColor.YELLOW) - .clickEvent(ClickEvent.runCommand("/bminfo " + nameData.getName())) + .clickEvent(ClickEvent.runCommand("/bminfo " + nameData.name())) .hoverEvent(Component.text(hoverText))); } diff --git a/common/src/main/java/me/confuser/banmanager/common/configs/DatabaseConfig.java b/common/src/main/java/me/confuser/banmanager/common/configs/DatabaseConfig.java index 64069d97a..1900e164b 100644 --- a/common/src/main/java/me/confuser/banmanager/common/configs/DatabaseConfig.java +++ b/common/src/main/java/me/confuser/banmanager/common/configs/DatabaseConfig.java @@ -79,20 +79,40 @@ private DatabaseConfig(File dataFolder, ConfigurationSection conf) { } public String getJDBCUrl() { - if (storageType.equals("h2")) return "jdbc:h2:file:" + new File(dataFolder, name).getAbsolutePath() + ";mode=MySQL;DB_CLOSE_ON_EXIT=TRUE;FILE_LOCK=NO;IGNORECASE=TRUE"; - - String url = "jdbc:" + storageType + "://" + host + ":" + port + "/" + name + - "?autoReconnect=true&failOverReadOnly=false&maxReconnects=10&useUnicode=true&characterEncoding=utf-8" + - "&serverTimezone=UTC" + - "&useSSL=" + useSSL + - "&allowPublicKeyRetrieval=" + allowPublicKeyRetrieval + - "&verifyServerCertificate=" + verifyServerCertificate; + if (storageType.equals("h2")) { + return "jdbc:h2:file:" + new File(dataFolder, name).getAbsolutePath() + + ";mode=MySQL;DB_CLOSE_ON_EXIT=TRUE;FILE_LOCK=NO;IGNORECASE=TRUE"; + } - if (!storageType.equals("mariadb")) { - url += "&disableMariaDbDriver"; + if (storageType.equals("mariadb")) { + // mariadb-java-client 3.x rejects most legacy mysql parameters with a WARN log. + // Only emit options the driver actually supports and translate useSSL + + // verifyServerCertificate into the modern sslMode setting. + String sslMode; + if (!useSSL) { + sslMode = "disable"; + } else if (verifyServerCertificate) { + sslMode = "verify-full"; + } else { + sslMode = "trust"; + } + return "jdbc:mariadb://" + host + ":" + port + "/" + name + + "?useServerPrepStmts=true" + + "&cachePrepStmts=true" + + "&prepStmtCacheSize=250" + + "&prepStmtCacheSqlLimit=2048" + + "&sslMode=" + sslMode; } - return url; + // mysql via mysql-connector-j 8.x. mariadb-java-client 3.x no longer hijacks + // jdbc:mysql:// URLs, so the legacy "disableMariaDbDriver" hint is gone. + return "jdbc:mysql://" + host + ":" + port + "/" + name + + "?autoReconnect=true&failOverReadOnly=false&maxReconnects=10" + + "&useUnicode=true&characterEncoding=utf-8" + + "&serverTimezone=UTC" + + "&useSSL=" + useSSL + + "&allowPublicKeyRetrieval=" + allowPublicKeyRetrieval + + "&verifyServerCertificate=" + verifyServerCertificate; } public DatabaseTableConfig getTable(String table) { diff --git a/common/src/main/java/me/confuser/banmanager/common/configs/Fetcher.java b/common/src/main/java/me/confuser/banmanager/common/configs/Fetcher.java index 7cf6f9483..9cda06a83 100644 --- a/common/src/main/java/me/confuser/banmanager/common/configs/Fetcher.java +++ b/common/src/main/java/me/confuser/banmanager/common/configs/Fetcher.java @@ -1,13 +1,4 @@ package me.confuser.banmanager.common.configs; -import lombok.AllArgsConstructor; -import lombok.Getter; - -@AllArgsConstructor -public -class Fetcher { - @Getter - private final String url; - @Getter - private final String key; +public record Fetcher(String url, String key) { } diff --git a/common/src/main/java/me/confuser/banmanager/common/configs/GeoIpConfig.java b/common/src/main/java/me/confuser/banmanager/common/configs/GeoIpConfig.java index 5c4ae4c78..cedb29992 100644 --- a/common/src/main/java/me/confuser/banmanager/common/configs/GeoIpConfig.java +++ b/common/src/main/java/me/confuser/banmanager/common/configs/GeoIpConfig.java @@ -1,6 +1,7 @@ package me.confuser.banmanager.common.configs; import lombok.Getter; +import me.confuser.banmanager.common.BanManagerPlugin; import me.confuser.banmanager.common.CommonLogger; import me.confuser.banmanager.common.apachecommons.compress.archivers.ArchiveEntry; import me.confuser.banmanager.common.apachecommons.compress.archivers.tar.TarArchiveInputStream; @@ -14,8 +15,11 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URL; -import java.net.URLConnection; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; import java.util.HashSet; import java.util.zip.GZIPInputStream; @@ -141,17 +145,32 @@ private void downloadDatabase(String downloadUrl, File location) throws IOExcept location.delete(); } - URL url = new URL(downloadUrl); - URLConnection con = url.openConnection(); + HttpClient client = BanManagerPlugin.getInstance().getHttpClient(); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(downloadUrl)) + .timeout(Duration.ofMinutes(5)) + .header("User-Agent", "BanManager") + .GET() + .build(); + + HttpResponse response; + try { + response = client.send(request, HttpResponse.BodyHandlers.ofInputStream()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Interrupted while downloading " + downloadUrl, e); + } - con.setConnectTimeout(6000); - con.connect(); + if (response.statusCode() != 200) { + response.body().close(); + throw new IOException("Unexpected response " + response.statusCode() + " from " + downloadUrl); + } - try (InputStream input = new GZIPInputStream(con.getInputStream()); + try (InputStream input = new GZIPInputStream(response.body()); TarArchiveInputStream inputStream = new TarArchiveInputStream(input); FileOutputStream outputStream = new FileOutputStream(location)) { - ArchiveEntry entry = null; + ArchiveEntry entry; while ((entry = inputStream.getNextEntry()) != null) { if (entry.isDirectory()) continue; if (!entry.getName().endsWith(".mmdb")) continue; diff --git a/common/src/main/java/me/confuser/banmanager/common/configs/Hook.java b/common/src/main/java/me/confuser/banmanager/common/configs/Hook.java index c97840577..5cd5d1add 100644 --- a/common/src/main/java/me/confuser/banmanager/common/configs/Hook.java +++ b/common/src/main/java/me/confuser/banmanager/common/configs/Hook.java @@ -1,25 +1,19 @@ package me.confuser.banmanager.common.configs; -import lombok.Getter; - import java.util.List; -public class Hook { - - @Getter - private final List pre; - @Getter - private final List post; - @Getter - private final boolean ignoreSilent; +/** + * Immutable description of a punishment-event hook (commands to run before + * and/or after the event fires). Lists are defensively copied so callers + * cannot mutate the hook's identity after construction. + */ +public record Hook(List pre, List post, boolean ignoreSilent) { + public Hook { + pre = pre == null ? List.of() : List.copyOf(pre); + post = post == null ? List.of() : List.copyOf(post); + } public Hook(List pre, List post) { this(pre, post, true); } - - public Hook(List pre, List post, boolean ignoreSilent) { - this.pre = pre; - this.post = post; - this.ignoreSilent = ignoreSilent; - } } diff --git a/common/src/main/java/me/confuser/banmanager/common/configs/PluginInfo.java b/common/src/main/java/me/confuser/banmanager/common/configs/PluginInfo.java index 4ccd573cb..0f1625239 100644 --- a/common/src/main/java/me/confuser/banmanager/common/configs/PluginInfo.java +++ b/common/src/main/java/me/confuser/banmanager/common/configs/PluginInfo.java @@ -1,8 +1,5 @@ package me.confuser.banmanager.common.configs; -import lombok.AllArgsConstructor; -import lombok.Getter; - import java.util.HashMap; import java.util.List; import java.util.Map; @@ -19,18 +16,9 @@ public CommandInfo getCommand(String commandName) { } public CommandInfo setCommand(CommandInfo command) { - return commands.put(command.getName(), command); + return commands.put(command.name(), command); } - @AllArgsConstructor - public static class CommandInfo { - @Getter - private String name; - @Getter - private String permission; - @Getter - private String usage; - @Getter - private List aliases; + public record CommandInfo(String name, String permission, String usage, List aliases) { } } diff --git a/common/src/main/java/me/confuser/banmanager/common/configs/UUIDFetcher.java b/common/src/main/java/me/confuser/banmanager/common/configs/UUIDFetcher.java index 02b4d2919..ac4166075 100644 --- a/common/src/main/java/me/confuser/banmanager/common/configs/UUIDFetcher.java +++ b/common/src/main/java/me/confuser/banmanager/common/configs/UUIDFetcher.java @@ -1,13 +1,4 @@ package me.confuser.banmanager.common.configs; -import lombok.AllArgsConstructor; -import lombok.Getter; - -@AllArgsConstructor -public class UUIDFetcher { - @Getter - private final Fetcher idToName; - @Getter - private final Fetcher nameToId; +public record UUIDFetcher(Fetcher idToName, Fetcher nameToId) { } - diff --git a/common/src/main/java/me/confuser/banmanager/common/configs/WebhookConfig.java b/common/src/main/java/me/confuser/banmanager/common/configs/WebhookConfig.java index b4c2ded74..9364dcf15 100644 --- a/common/src/main/java/me/confuser/banmanager/common/configs/WebhookConfig.java +++ b/common/src/main/java/me/confuser/banmanager/common/configs/WebhookConfig.java @@ -1,26 +1,26 @@ package me.confuser.banmanager.common.configs; -import lombok.AllArgsConstructor; import lombok.Getter; import me.confuser.banmanager.common.CommonLogger; import me.confuser.banmanager.common.configuration.ConfigurationSection; +import me.confuser.banmanager.common.data.Webhook; import me.confuser.banmanager.common.gson.Gson; import me.confuser.banmanager.common.gson.GsonBuilder; import java.io.File; import java.io.StringWriter; -import java.net.MalformedURLException; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.util.*; public class WebhookConfig extends Config { - private static final Set ALLOWED_METHODS = new HashSet<>(Arrays.asList( + private static final Set ALLOWED_METHODS = Set.of( "GET", "POST", "PUT", "PATCH", "DELETE" - )); + ); @Getter private boolean hooksEnabled = false; - private Map> hookTypes = new HashMap<>(); + private Map> hookTypes = new HashMap<>(); public WebhookConfig(File dataFolder, CommonLogger logger) { super(dataFolder, "webhooks.yml", logger); @@ -55,18 +55,16 @@ public void afterLoad() { } for (String type : hooks.getKeys(false)) { - List webhooksList = new ArrayList<>(); + List webhooksList = new ArrayList<>(); Object typeValue = hooks.get(type); - if (typeValue instanceof List) { - // New array format - List hookList = (List) typeValue; + if (typeValue instanceof List hookList) { int index = 0; for (Object hookObj : hookList) { if (hookObj instanceof Map) { @SuppressWarnings("unchecked") Map hookMap = (Map) hookObj; - WebhookHookConfig config = parseWebhookConfig(hookMap, type, index); + Webhook config = parseWebhookConfig(hookMap, type, index); if (config != null) { webhooksList.add(config); } @@ -77,7 +75,7 @@ public void afterLoad() { // Legacy single-object format - wrap in list ConfigurationSection hookSection = hooks.getConfigurationSection(type); if (hookSection != null) { - WebhookHookConfig config = parseLegacyWebhookConfig(hookSection, type); + Webhook config = parseLegacyWebhookConfig(hookSection, type); if (config != null) { webhooksList.add(config); } @@ -88,7 +86,7 @@ public void afterLoad() { } } - private WebhookHookConfig parseWebhookConfig(Map hookMap, String type, int index) { + private Webhook parseWebhookConfig(Map hookMap, String type, int index) { String name = (String) hookMap.getOrDefault("name", "webhook-" + index); String url = (String) hookMap.get("url"); String method = ((String) hookMap.getOrDefault("method", "POST")).toUpperCase(); @@ -109,11 +107,9 @@ private WebhookHookConfig parseWebhookConfig(Map hookMap, String // Parse headers Map headers = new HashMap<>(); Object headersObj = hookMap.get("headers"); - if (headersObj instanceof Map) { - @SuppressWarnings("unchecked") - Map headersMap = (Map) headersObj; - for (Map.Entry entry : headersMap.entrySet()) { - headers.put(entry.getKey(), String.valueOf(entry.getValue())); + if (headersObj instanceof Map headersMap) { + for (Map.Entry entry : headersMap.entrySet()) { + headers.put(String.valueOf(entry.getKey()), String.valueOf(entry.getValue())); } } @@ -127,10 +123,10 @@ private WebhookHookConfig parseWebhookConfig(Map hookMap, String payload = writer.toString(); } - return new WebhookHookConfig(name, url, method, headers, payload, ignoreSilent); + return new Webhook(name, url, method, headers, payload, ignoreSilent); } - private WebhookHookConfig parseLegacyWebhookConfig(ConfigurationSection hookSection, String type) { + private Webhook parseLegacyWebhookConfig(ConfigurationSection hookSection, String type) { String url = hookSection.getString("url"); String method = hookSection.getString("method", "POST").toUpperCase(); boolean ignoreSilent = hookSection.getBoolean("ignoreSilent", true); @@ -166,7 +162,7 @@ private WebhookHookConfig parseLegacyWebhookConfig(ConfigurationSection hookSect payload = writer.toString(); } - return new WebhookHookConfig("webhook-0", url, method, headers, payload, ignoreSilent); + return new Webhook("webhook-0", url, method, headers, payload, ignoreSilent); } private boolean isValidUrl(String url) { @@ -174,10 +170,12 @@ private boolean isValidUrl(String url) { return false; } try { - URL parsed = new URL(url); - String protocol = parsed.getProtocol().toLowerCase(); - return "http".equals(protocol) || "https".equals(protocol); - } catch (MalformedURLException e) { + URI parsed = new URI(url); + String scheme = parsed.getScheme(); + if (scheme == null) return false; + scheme = scheme.toLowerCase(Locale.ROOT); + return ("http".equals(scheme) || "https".equals(scheme)) && parsed.getHost() != null; + } catch (URISyntaxException e) { return false; } } @@ -186,24 +184,8 @@ private boolean isValidUrl(String url) { public void onSave() { } - public List getHooks(String type) { - List hooks = hookTypes.get(type); + public List getHooks(String type) { + List hooks = hookTypes.get(type); return hooks != null ? hooks : Collections.emptyList(); } - - @AllArgsConstructor - public static class WebhookHookConfig { - @Getter - private String name; - @Getter - private String url; - @Getter - private String method; - @Getter - private Map headers; - @Getter - private String payload; - @Getter - private boolean ignoreSilent; - } } diff --git a/common/src/main/java/me/confuser/banmanager/common/configuration/file/YamlConfiguration.java b/common/src/main/java/me/confuser/banmanager/common/configuration/file/YamlConfiguration.java index 363a2202b..d808d2dd1 100644 --- a/common/src/main/java/me/confuser/banmanager/common/configuration/file/YamlConfiguration.java +++ b/common/src/main/java/me/confuser/banmanager/common/configuration/file/YamlConfiguration.java @@ -5,6 +5,7 @@ import me.confuser.banmanager.common.configuration.ConfigurationSection; import me.confuser.banmanager.common.configuration.InvalidConfigurationException; import me.confuser.banmanager.common.snakeyaml.DumperOptions; +import me.confuser.banmanager.common.snakeyaml.LoaderOptions; import me.confuser.banmanager.common.snakeyaml.Yaml; import me.confuser.banmanager.common.snakeyaml.error.YAMLException; import me.confuser.banmanager.common.snakeyaml.representer.Representer; @@ -23,8 +24,34 @@ public class YamlConfiguration extends FileConfiguration { private static final String COMMENT_PREFIX = "# "; private static final String BLANK_CONFIG = "{}\n"; private final DumperOptions yamlOptions = new DumperOptions(); - private final Representer yamlRepresenter = new YamlRepresenter(); - private final Yaml yaml = new Yaml(new YamlConstructor(), yamlRepresenter, yamlOptions); + private final LoaderOptions loaderOptions = createLoaderOptions(); + private final Representer yamlRepresenter = new YamlRepresenter(yamlOptions); + private final Yaml yaml = new Yaml(new YamlConstructor(loaderOptions), yamlRepresenter, yamlOptions, loaderOptions); + + /** + * Build {@link LoaderOptions} that preserve SnakeYAML 1.x-compatible + * behaviour for existing user-authored config files. The 2.x defaults made + * three potentially breaking changes for our use case: + * + *
    + *
  • {@code allowDuplicateKeys} flipped from {@code true} to {@code false}. + * Operators routinely hand-edit messages.yml and may have introduced + * duplicate keys; refusing to load would brick the plugin on upgrade. The + * last value still wins, matching legacy behaviour.
  • + *
  • {@code codePointLimit} now defaults to 3 MB. Large message bundles + * (translations, big punishment payloads) can exceed this, so we raise it + * to 32 MB.
  • + *
  • {@code nestingDepthLimit} now defaults to 50. Bumped to 100 to give + * headroom for deeply nested webhook payloads.
  • + *
+ */ + private static LoaderOptions createLoaderOptions() { + LoaderOptions options = new LoaderOptions(); + options.setAllowDuplicateKeys(true); + options.setCodePointLimit(32 * 1024 * 1024); + options.setNestingDepthLimit(100); + return options; + } /** * Creates a new {@link YamlConfiguration}, loading from the given file. diff --git a/common/src/main/java/me/confuser/banmanager/common/configuration/file/YamlConstructor.java b/common/src/main/java/me/confuser/banmanager/common/configuration/file/YamlConstructor.java index 11bdba4fe..b75174e71 100644 --- a/common/src/main/java/me/confuser/banmanager/common/configuration/file/YamlConstructor.java +++ b/common/src/main/java/me/confuser/banmanager/common/configuration/file/YamlConstructor.java @@ -1,6 +1,7 @@ package me.confuser.banmanager.common.configuration.file; import me.confuser.banmanager.common.configuration.serialization.ConfigurationSerialization; +import me.confuser.banmanager.common.snakeyaml.LoaderOptions; import me.confuser.banmanager.common.snakeyaml.constructor.SafeConstructor; import me.confuser.banmanager.common.snakeyaml.error.YAMLException; import me.confuser.banmanager.common.snakeyaml.nodes.Node; @@ -11,7 +12,8 @@ public class YamlConstructor extends SafeConstructor { - YamlConstructor() { + YamlConstructor(LoaderOptions loaderOptions) { + super(loaderOptions); yamlConstructors.put(Tag.MAP, new ConstructCustomObject()); } diff --git a/common/src/main/java/me/confuser/banmanager/common/configuration/file/YamlRepresenter.java b/common/src/main/java/me/confuser/banmanager/common/configuration/file/YamlRepresenter.java index 3963d7fd5..e938e2346 100644 --- a/common/src/main/java/me/confuser/banmanager/common/configuration/file/YamlRepresenter.java +++ b/common/src/main/java/me/confuser/banmanager/common/configuration/file/YamlRepresenter.java @@ -3,6 +3,7 @@ import me.confuser.banmanager.common.configuration.ConfigurationSection; import me.confuser.banmanager.common.configuration.serialization.ConfigurationSerializable; import me.confuser.banmanager.common.configuration.serialization.ConfigurationSerialization; +import me.confuser.banmanager.common.snakeyaml.DumperOptions; import me.confuser.banmanager.common.snakeyaml.nodes.Node; import me.confuser.banmanager.common.snakeyaml.representer.Representer; @@ -11,7 +12,8 @@ class YamlRepresenter extends Representer { - YamlRepresenter() { + YamlRepresenter(DumperOptions options) { + super(options); this.multiRepresenters.put(ConfigurationSection.class, new RepresentConfigurationSection()); this.multiRepresenters .put(ConfigurationSerializable.class, new RepresentConfigurationSerializable()); diff --git a/common/src/main/java/me/confuser/banmanager/common/data/HistoryEntry.java b/common/src/main/java/me/confuser/banmanager/common/data/HistoryEntry.java index fa39dce0f..72382d837 100644 --- a/common/src/main/java/me/confuser/banmanager/common/data/HistoryEntry.java +++ b/common/src/main/java/me/confuser/banmanager/common/data/HistoryEntry.java @@ -1,33 +1,4 @@ package me.confuser.banmanager.common.data; -import lombok.Getter; - -public class HistoryEntry { - - @Getter - private final int id; - - @Getter - private final String type; - - @Getter - private final String actor; - - @Getter - private final long created; - - @Getter - private final String reason; - - @Getter - private final String meta; - - public HistoryEntry(int id, String type, String actor, long created, String reason, String meta) { - this.id = id; - this.type = type; - this.actor = actor; - this.created = created; - this.reason = reason; - this.meta = meta; - } +public record HistoryEntry(int id, String type, String actor, long created, String reason, String meta) { } diff --git a/common/src/main/java/me/confuser/banmanager/common/data/PlayerNameSummary.java b/common/src/main/java/me/confuser/banmanager/common/data/PlayerNameSummary.java index 5bcafd8cb..de2886856 100644 --- a/common/src/main/java/me/confuser/banmanager/common/data/PlayerNameSummary.java +++ b/common/src/main/java/me/confuser/banmanager/common/data/PlayerNameSummary.java @@ -1,25 +1,8 @@ package me.confuser.banmanager.common.data; -import lombok.Getter; - /** * Summary of a player's usage of a particular name. * Aggregated from interval history: firstSeen = min(fromSeen), lastSeen = max(toSeen or current time). */ -public class PlayerNameSummary { - - @Getter - private final String name; - - @Getter - private final long firstSeen; - - @Getter - private final long lastSeen; - - public PlayerNameSummary(String name, long firstSeen, long lastSeen) { - this.name = name; - this.firstSeen = firstSeen; - this.lastSeen = lastSeen; - } +public record PlayerNameSummary(String name, long firstSeen, long lastSeen) { } diff --git a/common/src/main/java/me/confuser/banmanager/common/data/Webhook.java b/common/src/main/java/me/confuser/banmanager/common/data/Webhook.java new file mode 100644 index 000000000..6341e0512 --- /dev/null +++ b/common/src/main/java/me/confuser/banmanager/common/data/Webhook.java @@ -0,0 +1,43 @@ +package me.confuser.banmanager.common.data; + +import java.util.List; +import java.util.Map; + +/** + * Immutable description of a webhook to send for a punishment event. + * + *

The same shape is used both for raw, parsed webhooks loaded from + * {@code webhooks.yml} (with placeholders such as {@code [player]} still in + * the headers/payload) and for the resolved webhook that is dispatched over + * HTTP. Treating both as the same value class avoids near-duplicate records + * and keeps the placeholder substitution a pure transformation.

+ * + *

{@code headers} are defensively copied at construction time so callers + * may pass mutable maps without leaking them into the record's identity.

+ */ +public record Webhook(String name, String url, String method, + Map headers, String payload, + boolean ignoreSilent) { + public Webhook { + headers = headers == null ? Map.of() : Map.copyOf(headers); + if (payload == null) payload = ""; + } + + /** + * Returns a copy of this webhook with new {@code headers} and {@code payload}. + * Use this when applying placeholder substitutions to a raw config webhook. + */ + public Webhook withResolved(Map resolvedHeaders, String resolvedPayload) { + return new Webhook(name, url, method, resolvedHeaders, resolvedPayload, ignoreSilent); + } + + /** True if this webhook has no body to send (GET/DELETE methods). */ + public boolean hasBody() { + return !"GET".equals(method) && !"DELETE".equals(method); + } + + /** Convenience for callers that only need a stable list-of-empty default. */ + public static List empty() { + return List.of(); + } +} diff --git a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonHooksListener.java b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonHooksListener.java index 86e346798..bf91db048 100755 --- a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonHooksListener.java +++ b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonHooksListener.java @@ -19,7 +19,7 @@ public CommonHooksListener(BanManagerPlugin plugin) { } private boolean shouldSkip(Hook hook, boolean silent) { - return silent && hook.isIgnoreSilent(); + return silent && hook.ignoreSilent(); } public void onBan(PlayerBanData data, boolean pre) { @@ -33,7 +33,7 @@ public void onBan(PlayerBanData data, boolean pre, boolean silent) { if (hook == null) return; if (shouldSkip(hook, silent)) return; - List commands = pre ? hook.getPre() : hook.getPost(); + List commands = pre ? hook.pre() : hook.post(); if (commands.size() != 0) { executeCommands(commands, ImmutableMap.of( @@ -57,8 +57,8 @@ public void onUnban(PlayerBanData data, PlayerData actor, String reason, boolean if (hook == null) return; if (shouldSkip(hook, silent)) return; - if (hook.getPost().size() != 0) { - executeCommands(hook.getPost(), ImmutableMap.of( + if (hook.post().size() != 0) { + executeCommands(hook.post(), ImmutableMap.of( "player", data.getPlayer().getName() , "playerId", data.getPlayer().getUUID().toString() , "actor", actor.getName() @@ -79,7 +79,7 @@ public void onMute(PlayerMuteData data, boolean pre, boolean silent) { if (hook == null) return; if (shouldSkip(hook, silent)) return; - List commands = pre ? hook.getPre() : hook.getPost(); + List commands = pre ? hook.pre() : hook.post(); if (commands.size() != 0) { executeCommands(commands, ImmutableMap.of( @@ -103,8 +103,8 @@ public void onUnmute(PlayerMuteData data, PlayerData actor, String reason, boole if (hook == null) return; if (shouldSkip(hook, silent)) return; - if (hook.getPost().size() != 0) { - executeCommands(hook.getPost(), ImmutableMap.of( + if (hook.post().size() != 0) { + executeCommands(hook.post(), ImmutableMap.of( "player", data.getPlayer().getName() , "playerId", data.getPlayer().getUUID().toString() , "actor", actor.getName() @@ -125,7 +125,7 @@ public void onBan(IpBanData data, boolean pre, boolean silent) { if (hook == null) return; if (shouldSkip(hook, silent)) return; - List commands = pre ? hook.getPre() : hook.getPost(); + List commands = pre ? hook.pre() : hook.post(); if (commands.size() != 0) { executeCommands(commands, ImmutableMap.of( @@ -148,8 +148,8 @@ public void onUnban(IpBanData data, PlayerData actor, String reason, boolean sil if (hook == null) return; if (shouldSkip(hook, silent)) return; - if (hook.getPost().size() != 0) { - executeCommands(hook.getPost(), ImmutableMap.of( + if (hook.post().size() != 0) { + executeCommands(hook.post(), ImmutableMap.of( "ip", data.getIp().toString() , "actor", actor.getName() , "reason", reason @@ -170,7 +170,7 @@ public void onBan(IpRangeBanData data, boolean pre, boolean silent) { if (hook == null) return; if (shouldSkip(hook, silent)) return; - List commands = pre ? hook.getPre() : hook.getPost(); + List commands = pre ? hook.pre() : hook.post(); if (commands.size() != 0) { executeCommands(commands, ImmutableMap.of( @@ -194,8 +194,8 @@ public void onUnban(IpRangeBanData data, PlayerData actor, String reason, boolea if (hook == null) return; if (shouldSkip(hook, silent)) return; - if (hook.getPost().size() != 0) { - executeCommands(hook.getPost(), ImmutableMap.of( + if (hook.post().size() != 0) { + executeCommands(hook.post(), ImmutableMap.of( "from", data.getFromIp().toString() , "to", data.getToIp().toString() , "actor", actor.getName() @@ -216,7 +216,7 @@ public void onWarn(PlayerWarnData data, boolean pre, boolean silent) { if (hook == null) return; if (shouldSkip(hook, silent)) return; - List commands = pre ? hook.getPre() : hook.getPost(); + List commands = pre ? hook.pre() : hook.post(); if (commands.size() != 0) { executeCommands(commands, ImmutableMap.of( @@ -240,8 +240,8 @@ public void onNote(PlayerNoteData data, boolean silent) { if (hook == null) return; if (shouldSkip(hook, silent)) return; - if (hook.getPost().size() != 0) { - executeCommands(hook.getPost(), ImmutableMap.of( + if (hook.post().size() != 0) { + executeCommands(hook.post(), ImmutableMap.of( "player", data.getPlayer().getName() , "playerId", data.getPlayer().getUUID().toString() , "actor", data.getActor().getName() @@ -261,7 +261,7 @@ public void onReport(PlayerReportData data, boolean pre, boolean silent) { if (hook == null) return; if (shouldSkip(hook, silent)) return; - List commands = pre ? hook.getPre() : hook.getPost(); + List commands = pre ? hook.pre() : hook.post(); if (commands.size() != 0) { executeCommands(commands, ImmutableMap.of( diff --git a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonWebhookListener.java b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonWebhookListener.java index 87881062a..b5e14b49a 100644 --- a/common/src/main/java/me/confuser/banmanager/common/listeners/CommonWebhookListener.java +++ b/common/src/main/java/me/confuser/banmanager/common/listeners/CommonWebhookListener.java @@ -1,7 +1,6 @@ package me.confuser.banmanager.common.listeners; import me.confuser.banmanager.common.BanManagerPlugin; -import me.confuser.banmanager.common.configs.WebhookConfig.WebhookHookConfig; import me.confuser.banmanager.common.data.*; import me.confuser.banmanager.common.util.DateUtils; @@ -9,15 +8,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.net.HttpURLConnection; +import java.net.URI; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.time.Duration; import java.time.format.DateTimeFormatter; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.URL; import java.sql.SQLException; import java.time.ZoneId; @@ -33,10 +30,9 @@ private String toISO8601(long timestamp) { .format(java.time.Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault())); } - public List notifyOnBan(PlayerBanData ban) { + public List notifyOnBan(PlayerBanData ban) { String type = ban.getExpires() == 0 ? "ban" : "tempban"; - List hooks = plugin.getWebhookConfig().getHooks(type); - List results = new ArrayList<>(); + List hooks = plugin.getWebhookConfig().getHooks(type); Map replacements = new HashMap<>(); replacements.put("[player]", ban.getPlayer().getName()); @@ -51,17 +47,12 @@ public List notifyOnBan(PlayerBanData ban) { replacements.put("[expires]", DateUtils.getDifferenceFormat(ban.getExpires())); } - for (WebhookHookConfig hook : hooks) { - results.add(createWebhookData(hook, replacements)); - } - - return results; + return resolve(hooks, replacements); } - public List notifyOnBan(IpBanData ban) { + public List notifyOnBan(IpBanData ban) { String type = ban.getExpires() == 0 ? "banip" : "tempbanip"; - List hooks = plugin.getWebhookConfig().getHooks(type); - List results = new ArrayList<>(); + List hooks = plugin.getWebhookConfig().getHooks(type); List players = plugin.getPlayerStorage().getDuplicatesInTime(ban.getIp(), plugin.getConfig().getTimeAssociatedAlts()); @@ -87,16 +78,11 @@ public List notifyOnBan(IpBanData ban) { replacements.put("[expires]", DateUtils.getDifferenceFormat(ban.getExpires())); } - for (WebhookHookConfig hook : hooks) { - results.add(createWebhookData(hook, replacements)); - } - - return results; + return resolve(hooks, replacements); } - public List notifyOnKick(PlayerKickData kick) { - List hooks = plugin.getWebhookConfig().getHooks("kick"); - List results = new ArrayList<>(); + public List notifyOnKick(PlayerKickData kick) { + List hooks = plugin.getWebhookConfig().getHooks("kick"); Map replacements = new HashMap<>(); replacements.put("[player]", kick.getPlayer().getName()); @@ -107,17 +93,12 @@ public List notifyOnKick(PlayerKickData kick) { replacements.put("[created]", toISO8601(kick.getCreated())); replacements.put("[reason]", kick.getReason()); - for (WebhookHookConfig hook : hooks) { - results.add(createWebhookData(hook, replacements)); - } - - return results; + return resolve(hooks, replacements); } - public List notifyOnMute(PlayerMuteData mute) { + public List notifyOnMute(PlayerMuteData mute) { String type = mute.getExpires() == 0 ? "mute" : "tempmute"; - List hooks = plugin.getWebhookConfig().getHooks(type); - List results = new ArrayList<>(); + List hooks = plugin.getWebhookConfig().getHooks(type); Map replacements = new HashMap<>(); replacements.put("[player]", mute.getPlayer().getName()); @@ -132,17 +113,12 @@ public List notifyOnMute(PlayerMuteData mute) { replacements.put("[expires]", DateUtils.getDifferenceFormat(mute.getExpires())); } - for (WebhookHookConfig hook : hooks) { - results.add(createWebhookData(hook, replacements)); - } - - return results; + return resolve(hooks, replacements); } - public List notifyOnWarn(PlayerWarnData warn) { + public List notifyOnWarn(PlayerWarnData warn) { String type = warn.getExpires() == 0 ? "warning" : "tempwarning"; - List hooks = plugin.getWebhookConfig().getHooks(type); - List results = new ArrayList<>(); + List hooks = plugin.getWebhookConfig().getHooks(type); Map replacements = new HashMap<>(); replacements.put("[player]", warn.getPlayer().getName()); @@ -158,16 +134,11 @@ public List notifyOnWarn(PlayerWarnData warn) { replacements.put("[expires]", DateUtils.getDifferenceFormat(warn.getExpires())); } - for (WebhookHookConfig hook : hooks) { - results.add(createWebhookData(hook, replacements)); - } - - return results; + return resolve(hooks, replacements); } - public List notifyOnUnban(PlayerBanData ban, PlayerData actor, String reason) { - List hooks = plugin.getWebhookConfig().getHooks("unban"); - List results = new ArrayList<>(); + public List notifyOnUnban(PlayerBanData ban, PlayerData actor, String reason) { + List hooks = plugin.getWebhookConfig().getHooks("unban"); Map replacements = new HashMap<>(); replacements.put("[player]", ban.getPlayer().getName()); @@ -178,16 +149,11 @@ public List notifyOnUnban(PlayerBanData ban, PlayerData actor, Stri replacements.put("[created]", toISO8601(ban.getCreated())); replacements.put("[reason]", reason); - for (WebhookHookConfig hook : hooks) { - results.add(createWebhookData(hook, replacements)); - } - - return results; + return resolve(hooks, replacements); } - public List notifyOnUnban(IpBanData ban, PlayerData actor, String reason) { - List hooks = plugin.getWebhookConfig().getHooks("unbanip"); - List results = new ArrayList<>(); + public List notifyOnUnban(IpBanData ban, PlayerData actor, String reason) { + List hooks = plugin.getWebhookConfig().getHooks("unbanip"); Map replacements = new HashMap<>(); replacements.put("[ip]", ban.getIp().toString()); @@ -197,16 +163,11 @@ public List notifyOnUnban(IpBanData ban, PlayerData actor, String r replacements.put("[created]", toISO8601(ban.getCreated())); replacements.put("[reason]", reason); - for (WebhookHookConfig hook : hooks) { - results.add(createWebhookData(hook, replacements)); - } - - return results; + return resolve(hooks, replacements); } - public List notifyOnUnmute(PlayerMuteData mute, PlayerData actor, String reason) { - List hooks = plugin.getWebhookConfig().getHooks("unmute"); - List results = new ArrayList<>(); + public List notifyOnUnmute(PlayerMuteData mute, PlayerData actor, String reason) { + List hooks = plugin.getWebhookConfig().getHooks("unmute"); Map replacements = new HashMap<>(); replacements.put("[player]", mute.getPlayer().getName()); @@ -217,22 +178,17 @@ public List notifyOnUnmute(PlayerMuteData mute, PlayerData actor, S replacements.put("[created]", toISO8601(mute.getCreated())); replacements.put("[reason]", reason); - for (WebhookHookConfig hook : hooks) { - results.add(createWebhookData(hook, replacements)); - } - - return results; + return resolve(hooks, replacements); } - public List notifyOnReport(PlayerReportData report, PlayerData actor, String reason) { - List hooks = plugin.getWebhookConfig().getHooks("report"); - List results = new ArrayList<>(); + public List notifyOnReport(PlayerReportData report, PlayerData actor, String reason) { + List hooks = plugin.getWebhookConfig().getHooks("report"); List locations = null; try { locations = plugin.getPlayerReportLocationStorage().getByReport(report); } catch (SQLException e) { - plugin.getLogger().warning("Failed to send webhook", e); + plugin.getLogger().warning("Failed to load report locations for webhook", e); } Map replacements = new HashMap<>(); @@ -275,20 +231,24 @@ public List notifyOnReport(PlayerReportData report, PlayerData acto } } - for (WebhookHookConfig hook : hooks) { - results.add(createWebhookData(hook, replacements)); - } + return resolve(hooks, replacements); + } + private List resolve(List hooks, Map replacements) { + List results = new ArrayList<>(hooks.size()); + for (Webhook hook : hooks) { + results.add(applyReplacements(hook, replacements)); + } return results; } - private WebhookData createWebhookData(WebhookHookConfig hook, Map replacements) { - String payload = applyReplacements(hook.getPayload(), replacements); + private Webhook applyReplacements(Webhook hook, Map replacements) { + String payload = applyReplacements(hook.payload(), replacements); Map headers = new HashMap<>(); - for (Map.Entry entry : hook.getHeaders().entrySet()) { + for (Map.Entry entry : hook.headers().entrySet()) { headers.put(entry.getKey(), applyReplacements(entry.getValue(), replacements)); } - return new WebhookData(hook.getName(), hook.getUrl(), hook.getMethod(), headers, payload, hook.isIgnoreSilent()); + return hook.withResolved(headers, payload); } private String applyReplacements(String input, Map replacements) { @@ -300,87 +260,54 @@ private String applyReplacements(String input, Map replacements) return result; } - public void sendAsync(WebhookData data) { - CompletableFuture.runAsync(() -> send(data)); - } - - public void send(WebhookData data) { + public void sendAsync(Webhook data) { if (plugin.getConfig().isDebugEnabled()) { - plugin.getLogger().info("Sending webhook '" + data.name + "' to " + data.url + " with method " + data.method); + plugin.getLogger().info("Sending webhook '" + data.name() + "' to " + data.url() + " with method " + data.method()); } - HttpURLConnection connection = null; + HttpRequest request; try { - connection = (HttpURLConnection) new URL(data.url).openConnection(); - connection.addRequestProperty("Content-Type", "application/json"); - connection.addRequestProperty("User-Agent", "BanManager"); - - // Apply custom headers - for (Map.Entry header : data.headers.entrySet()) { - connection.addRequestProperty(header.getKey(), header.getValue()); - } - - connection.setRequestMethod(data.method); + request = buildRequest(data); + } catch (IllegalArgumentException e) { + plugin.getLogger().warning("Failed to send webhook '" + data.name() + "': invalid URL or method - " + e.getMessage()); + return; + } - // Only set output for methods that support a body - if (!"GET".equals(data.method) && !"DELETE".equals(data.method)) { - connection.setDoOutput(true); - try (OutputStream stream = connection.getOutputStream()) { - stream.write(data.payload.getBytes()); - stream.flush(); - } - } + plugin.getHttpClient() + .sendAsync(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)) + .whenComplete((response, throwable) -> { + if (throwable != null) { + plugin.getLogger().warning("Failed to send webhook '" + data.name() + "'", throwable); + return; + } - int responseCode = connection.getResponseCode(); - if (responseCode > 299) { - plugin.getLogger().warning("Failed to send webhook '" + data.name + "'"); - plugin.getLogger().warning("Response code: " + responseCode); - - InputStream errorStream = connection.getErrorStream(); - if (errorStream != null) { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream))) { - StringBuilder responseBody = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - responseBody.append(line); + int responseCode = response.statusCode(); + if (responseCode > 299) { + plugin.getLogger().warning("Failed to send webhook '" + data.name() + "'"); + plugin.getLogger().warning("Response code: " + responseCode); + String body = response.body(); + if (body != null && !body.isEmpty()) { + plugin.getLogger().warning("Response body: " + body); } - plugin.getLogger().warning("Response body: " + responseBody.toString()); } - } - } else { - try (InputStream in = connection.getInputStream()) { - while (in.read() != -1) {} - } - } - } catch (Exception e) { - plugin.getLogger().warning("Failed to send webhook '" + data.name + "'"); - plugin.getLogger().warning("Error: " + e.getMessage()); - plugin.getLogger().warning("Failed to send webhook", e); - } finally { - if (connection != null) { - connection.disconnect(); - } - } + }); } - /** - * Data class to hold all information needed to send a webhook request. - */ - public static class WebhookData { - public final String name; - public final String url; - public final String method; - public final Map headers; - public final String payload; - public final boolean ignoreSilent; - - public WebhookData(String name, String url, String method, Map headers, String payload, boolean ignoreSilent) { - this.name = name; - this.url = url; - this.method = method; - this.headers = headers; - this.payload = payload; - this.ignoreSilent = ignoreSilent; + private HttpRequest buildRequest(Webhook data) { + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create(data.url())) + .timeout(Duration.ofSeconds(15)) + .header("Content-Type", "application/json") + .header("User-Agent", "BanManager"); + + for (Map.Entry header : data.headers().entrySet()) { + builder.header(header.getKey(), header.getValue()); } + + HttpRequest.BodyPublisher body = data.hasBody() + ? HttpRequest.BodyPublishers.ofString(data.payload(), StandardCharsets.UTF_8) + : HttpRequest.BodyPublishers.noBody(); + + return builder.method(data.method(), body).build(); } } diff --git a/common/src/main/java/me/confuser/banmanager/common/runnables/RollbackSync.java b/common/src/main/java/me/confuser/banmanager/common/runnables/RollbackSync.java index bafaac7be..7b45a783a 100644 --- a/common/src/main/java/me/confuser/banmanager/common/runnables/RollbackSync.java +++ b/common/src/main/java/me/confuser/banmanager/common/runnables/RollbackSync.java @@ -28,65 +28,43 @@ public void run() { final RollbackData data = itr.next(); switch (data.getType()) { - case "bans": - evictFromCache(plugin.getPlayerBanStorage().getBans(), - v -> v.getActor().getUUID(), PlayerBanData::getCreated, data); - break; - - case "ipbans": - evictFromCache(plugin.getIpBanStorage().getBans(), - v -> v.getActor().getUUID(), IpBanData::getCreated, data); - break; - - case "ipmutes": - evictFromCache(plugin.getIpMuteStorage().getMutes(), - v -> v.getActor().getUUID(), IpMuteData::getCreated, data); - break; - - case "mutes": - evictFromCache(plugin.getPlayerMuteStorage().getMutes(), - v -> v.getActor().getUUID(), PlayerMuteData::getCreated, data); - break; - - case "banrecords": - restoreToCache(plugin.getPlayerBanStorage() - .queryBuilder().where() - .le("created", data.getCreated()) - .and().ge("created", data.getExpires()) - .iterator(), - ban -> !plugin.getPlayerBanStorage().isBanned(ban.getPlayer().getUUID()), - ban -> plugin.getPlayerBanStorage().addBan(ban)); - break; - - case "ipbanrecords": - restoreToCache(plugin.getIpBanStorage() - .queryBuilder().where() - .le("created", data.getCreated()) - .and().ge("created", data.getExpires()) - .iterator(), - ban -> !plugin.getIpBanStorage().isBanned(ban.getIp()), - ban -> plugin.getIpBanStorage().addBan(ban)); - break; - - case "muterecords": - restoreToCache(plugin.getPlayerMuteStorage() - .queryBuilder().where() - .le("created", data.getCreated()) - .and().ge("created", data.getExpires()) - .iterator(), - mute -> !plugin.getPlayerMuteStorage().isMuted(mute.getPlayer().getUUID()), - mute -> plugin.getPlayerMuteStorage().addMute(mute)); - break; - - case "ipmuterecords": - restoreToCache(plugin.getIpMuteStorage() - .queryBuilder().where() - .le("created", data.getCreated()) - .and().ge("created", data.getExpires()) - .iterator(), - mute -> !plugin.getIpMuteStorage().isMuted(mute.getIp()), - mute -> plugin.getIpMuteStorage().addMute(mute)); - break; + case "bans" -> evictFromCache(plugin.getPlayerBanStorage().getBans(), + v -> v.getActor().getUUID(), PlayerBanData::getCreated, data); + case "ipbans" -> evictFromCache(plugin.getIpBanStorage().getBans(), + v -> v.getActor().getUUID(), IpBanData::getCreated, data); + case "ipmutes" -> evictFromCache(plugin.getIpMuteStorage().getMutes(), + v -> v.getActor().getUUID(), IpMuteData::getCreated, data); + case "mutes" -> evictFromCache(plugin.getPlayerMuteStorage().getMutes(), + v -> v.getActor().getUUID(), PlayerMuteData::getCreated, data); + case "banrecords" -> restoreToCache(plugin.getPlayerBanStorage() + .queryBuilder().where() + .le("created", data.getCreated()) + .and().ge("created", data.getExpires()) + .iterator(), + ban -> !plugin.getPlayerBanStorage().isBanned(ban.getPlayer().getUUID()), + ban -> plugin.getPlayerBanStorage().addBan(ban)); + case "ipbanrecords" -> restoreToCache(plugin.getIpBanStorage() + .queryBuilder().where() + .le("created", data.getCreated()) + .and().ge("created", data.getExpires()) + .iterator(), + ban -> !plugin.getIpBanStorage().isBanned(ban.getIp()), + ban -> plugin.getIpBanStorage().addBan(ban)); + case "muterecords" -> restoreToCache(plugin.getPlayerMuteStorage() + .queryBuilder().where() + .le("created", data.getCreated()) + .and().ge("created", data.getExpires()) + .iterator(), + mute -> !plugin.getPlayerMuteStorage().isMuted(mute.getPlayer().getUUID()), + mute -> plugin.getPlayerMuteStorage().addMute(mute)); + case "ipmuterecords" -> restoreToCache(plugin.getIpMuteStorage() + .queryBuilder().where() + .le("created", data.getCreated()) + .and().ge("created", data.getExpires()) + .iterator(), + mute -> !plugin.getIpMuteStorage().isMuted(mute.getIp()), + mute -> plugin.getIpMuteStorage().addMute(mute)); + default -> { /* unknown rollback type */ } } } diff --git a/common/src/main/java/me/confuser/banmanager/common/storage/ActivityStorage.java b/common/src/main/java/me/confuser/banmanager/common/storage/ActivityStorage.java index 3b7f076a9..9454b4c62 100644 --- a/common/src/main/java/me/confuser/banmanager/common/storage/ActivityStorage.java +++ b/common/src/main/java/me/confuser/banmanager/common/storage/ActivityStorage.java @@ -7,10 +7,7 @@ import me.confuser.banmanager.common.ormlite.support.CompiledStatement; import me.confuser.banmanager.common.ormlite.support.DatabaseConnection; import me.confuser.banmanager.common.ormlite.support.DatabaseResults; -import me.confuser.banmanager.common.util.IPUtils; -import java.io.IOException; -import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -296,11 +293,11 @@ public List> getSince(long since, PlayerData actor) { result.closeQuietly(); } } finally { - try { statement.close(); } catch (IOException ignored) { } + try { statement.close(); } catch (Exception ignored) { } } return results; - } catch (SQLException | IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed to process activity operation", e); return null; } diff --git a/common/src/main/java/me/confuser/banmanager/common/storage/HistoryStorage.java b/common/src/main/java/me/confuser/banmanager/common/storage/HistoryStorage.java index 0a9e64489..7b0656d15 100644 --- a/common/src/main/java/me/confuser/banmanager/common/storage/HistoryStorage.java +++ b/common/src/main/java/me/confuser/banmanager/common/storage/HistoryStorage.java @@ -11,8 +11,6 @@ import me.confuser.banmanager.common.ormlite.support.DatabaseResults; import me.confuser.banmanager.common.util.parsers.InfoCommandParser; -import java.io.IOException; -import java.sql.SQLException; import java.util.ArrayList; import java.util.List; @@ -180,11 +178,11 @@ private List executeQuery(Object paramValue, SqlType paramType, dbResults.closeQuietly(); } } finally { - try { statement.close(); } catch (IOException ignored) { } + try { statement.close(); } catch (Exception ignored) { } } return results; - } catch (SQLException | IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed to process history operation", e); return null; } diff --git a/common/src/main/java/me/confuser/banmanager/common/storage/PlayerHistoryStorage.java b/common/src/main/java/me/confuser/banmanager/common/storage/PlayerHistoryStorage.java index 134dc4b77..3c80a3254 100644 --- a/common/src/main/java/me/confuser/banmanager/common/storage/PlayerHistoryStorage.java +++ b/common/src/main/java/me/confuser/banmanager/common/storage/PlayerHistoryStorage.java @@ -17,8 +17,8 @@ import me.confuser.banmanager.common.ormlite.support.CompiledStatement; import me.confuser.banmanager.common.ormlite.support.DatabaseConnection; import me.confuser.banmanager.common.ormlite.support.DatabaseResults; +import me.confuser.banmanager.common.util.StorageUtils; -import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; @@ -176,13 +176,13 @@ public List getNamesSummary(PlayerData player) throws SQLExce results.getLong(2))); } } finally { - try { results.close(); } catch (IOException ignored) { } + try { results.close(); } catch (Exception ignored) { } } } finally { - try { statement.close(); } catch (IOException ignored) { } + try { statement.close(); } catch (Exception ignored) { } } - } catch (IOException e) { - throw new SQLException("Failed to query name summary", e); + } catch (Exception e) { + throw StorageUtils.toSqlException("Failed to query name summary", e); } return summaries; diff --git a/common/src/main/java/me/confuser/banmanager/common/storage/PlayerWarnStorage.java b/common/src/main/java/me/confuser/banmanager/common/storage/PlayerWarnStorage.java index 59bae920d..8cf83da34 100644 --- a/common/src/main/java/me/confuser/banmanager/common/storage/PlayerWarnStorage.java +++ b/common/src/main/java/me/confuser/banmanager/common/storage/PlayerWarnStorage.java @@ -20,9 +20,9 @@ import me.confuser.banmanager.common.ormlite.support.DatabaseResults; import me.confuser.banmanager.common.ormlite.table.DatabaseTableConfig; import me.confuser.banmanager.common.ormlite.table.TableUtils; +import me.confuser.banmanager.common.util.StorageUtils; import me.confuser.banmanager.common.util.UUIDUtils; -import java.io.IOException; import java.sql.SQLException; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -108,7 +108,9 @@ public double getPointsCount(PlayerData player) throws SQLException { DatabaseResults results = statement.runQuery(null); if (results.next()) return results.getDouble(0); - } catch (IOException e) { + } catch (SQLException e) { + throw e; + } catch (Exception e) { plugin.getLogger().warning("Failed to process player warn operation", e); } @@ -127,7 +129,9 @@ public double getPointsCount(PlayerData player, long timeframe) throws SQLExcept DatabaseResults results = statement.runQuery(null); if (results.next()) return results.getDouble(0); - } catch (IOException e) { + } catch (SQLException e) { + throw e; + } catch (Exception e) { plugin.getLogger().warning("Failed to process player warn operation", e); } @@ -166,10 +170,10 @@ public int deleteRecent(PlayerData player) throws SQLException { statement.setObject(0, player.getId(), SqlType.BYTE_ARRAY); return statement.runUpdate(); } finally { - try { statement.close(); } catch (IOException ignored) { } + try { statement.close(); } catch (Exception ignored) { } } - } catch (IOException e) { - throw new SQLException("Failed to delete recent warning", e); + } catch (Exception e) { + throw StorageUtils.toSqlException("Failed to delete recent warning", e); } } diff --git a/common/src/main/java/me/confuser/banmanager/common/storage/conversion/H2.java b/common/src/main/java/me/confuser/banmanager/common/storage/conversion/H2.java index b847a6543..8d9d5cc5f 100644 --- a/common/src/main/java/me/confuser/banmanager/common/storage/conversion/H2.java +++ b/common/src/main/java/me/confuser/banmanager/common/storage/conversion/H2.java @@ -10,7 +10,6 @@ import me.confuser.banmanager.common.storage.*; import java.io.File; -import java.io.IOException; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; @@ -126,7 +125,7 @@ public void importPlayers() { plugin.getLogger().severe("Failed to import player " + data.getUUID()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -148,7 +147,7 @@ public void importPlayerBans() { plugin.getLogger().severe("Failed to import player ban " + data.getPlayer().getUUID()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -167,7 +166,7 @@ public void importPlayerBans() { plugin.getLogger().severe("Failed to import player ban record " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -189,7 +188,7 @@ public void importPlayerMutes() { plugin.getLogger().severe("Failed to import player mute " + data.getPlayer().getUUID()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -208,7 +207,7 @@ public void importPlayerMutes() { plugin.getLogger().severe("Failed to import player mute record " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -230,7 +229,7 @@ public void importPlayerWarnings() { plugin.getLogger().severe("Failed to import player warning " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -251,7 +250,7 @@ public void importPlayerKicks() { plugin.getLogger().severe("Failed to import player kick " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -272,7 +271,7 @@ public void importPlayerNotes() { plugin.getLogger().severe("Failed to import player note " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -293,7 +292,7 @@ public void importPlayerHistory() { plugin.getLogger().severe("Failed to import player note " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -326,7 +325,7 @@ public void importPlayerReports() { plugin.getLogger().severe("Failed to import player report state " + h2State.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -345,7 +344,7 @@ public void importPlayerReports() { plugin.getLogger().severe("Failed to import player report state " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -364,7 +363,7 @@ public void importPlayerReports() { plugin.getLogger().severe("Failed to import player report comment " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -410,7 +409,7 @@ public void importPlayerReports() { plugin.getLogger().severe("Failed to import player report " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -429,7 +428,7 @@ public void importPlayerReports() { plugin.getLogger().severe("Failed to import player report location " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -451,7 +450,7 @@ public void importIpBans() { plugin.getLogger().severe("Failed to import ip ban " + data.getIp()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -470,7 +469,7 @@ public void importIpBans() { plugin.getLogger().severe("Failed to import ip ban record " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -491,7 +490,7 @@ public void importIpMutes() { plugin.getLogger().severe("Failed to import ip mute " + data.getIp()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -510,7 +509,7 @@ public void importIpMutes() { plugin.getLogger().severe("Failed to import ip mute record " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -532,7 +531,7 @@ public void importIpRangeBans() { plugin.getLogger().severe("Failed to import ip range ban " + data.getFromIp() + " - " + data.getToIp()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -551,7 +550,7 @@ public void importIpRangeBans() { plugin.getLogger().severe("Failed to import ip range ban record " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -572,7 +571,7 @@ public void importNameBans() { plugin.getLogger().severe("Failed to import name ban " + data.getName()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } @@ -591,7 +590,7 @@ public void importNameBans() { plugin.getLogger().severe("Failed to import name ban record " + data.getId()); } } - } catch (IOException e) { + } catch (Exception e) { plugin.getLogger().warning("Failed during H2 conversion", e); } diff --git a/common/src/main/java/me/confuser/banmanager/common/storage/mariadb/MariaDBDatabase.java b/common/src/main/java/me/confuser/banmanager/common/storage/mariadb/MariaDBDatabase.java index afe75ccca..50451cc7b 100644 --- a/common/src/main/java/me/confuser/banmanager/common/storage/mariadb/MariaDBDatabase.java +++ b/common/src/main/java/me/confuser/banmanager/common/storage/mariadb/MariaDBDatabase.java @@ -1,6 +1,6 @@ package me.confuser.banmanager.common.storage.mariadb; -import me.confuser.banmanager.common.ormlite.db.MariaDbDatabaseType; +import me.confuser.banmanager.common.ormlite.jdbc.db.MariaDbDatabaseType; public class MariaDBDatabase extends MariaDbDatabaseType { diff --git a/common/src/main/java/me/confuser/banmanager/common/storage/migration/MigrationRunner.java b/common/src/main/java/me/confuser/banmanager/common/storage/migration/MigrationRunner.java index 6b358fda0..ac2937a03 100644 --- a/common/src/main/java/me/confuser/banmanager/common/storage/migration/MigrationRunner.java +++ b/common/src/main/java/me/confuser/banmanager/common/storage/migration/MigrationRunner.java @@ -9,6 +9,7 @@ import me.confuser.banmanager.common.ormlite.support.DatabaseConnection; import me.confuser.banmanager.common.ormlite.support.DatabaseResults; import me.confuser.banmanager.common.ormlite.table.TableUtils; +import me.confuser.banmanager.common.util.StorageUtils; import java.io.BufferedReader; import java.io.IOException; @@ -60,7 +61,7 @@ public void migrate() throws SQLException { String detectionTableName = dbConfig.getTable(detectionTableKey).getTableName(); - int latestVersion = migrations.get(migrations.size() - 1).version; + int latestVersion = migrations.get(migrations.size() - 1).version(); boolean isH2 = dbConfig.getStorageType().equals("h2"); DatabaseConnection conn = connectionSource.getReadWriteConnection(""); @@ -88,18 +89,18 @@ public void migrate() throws SQLException { int applied = 0; for (MigrationFile migration : migrations) { - if (migration.version <= currentVersion) { + if (migration.version() <= currentVersion) { continue; } - plugin.getLogger().info("[Migration:" + instanceScope + "] Applying V" + migration.version + " " + migration.description); - String sql = loadSqlFile(migration.filename); + plugin.getLogger().info("[Migration:" + instanceScope + "] Applying V" + migration.version() + " " + migration.description()); + String sql = loadSqlFile(migration.filename()); if (sql.isEmpty()) { - throw new SQLException("[Migration:" + instanceScope + "] Migration file not found or empty: " + migration.filename); + throw new SQLException("[Migration:" + instanceScope + "] Migration file not found or empty: " + migration.filename()); } sql = substitutePlaceholders(sql); - executeMigrationStatements(conn, sql, migration.lenient); - insertVersion(conn, migration.version, migration.description); + executeMigrationStatements(conn, sql, migration.lenient()); + insertVersion(conn, migration.version(), migration.description()); applied++; } @@ -117,21 +118,16 @@ public void migrate() throws SQLException { } private void acquireAdvisoryLock(DatabaseConnection conn) throws SQLException { - CompiledStatement stmt = conn.compileStatement( + try (CompiledStatement stmt = conn.compileStatement( "SELECT GET_LOCK('bm_migration_" + instanceScope + "', 30)", StatementBuilder.StatementType.SELECT, null, DatabaseConnection.DEFAULT_RESULT_FLAGS, false); - try { - DatabaseResults results = stmt.runQuery(null); - try { - if (!results.next() || results.getInt(0) != 1) { - throw new SQLException("[Migration:" + instanceScope + "] Could not acquire advisory lock (another server may be migrating)"); - } - } finally { - closeQuietly(results); + DatabaseResults results = stmt.runQuery(null)) { + if (!results.next() || results.getInt(0) != 1) { + throw new SQLException("[Migration:" + instanceScope + "] Could not acquire advisory lock (another server may be migrating)"); } - } finally { - closeQuietly(stmt); + } catch (Exception e) { + throw StorageUtils.toSqlException("[Migration:" + instanceScope + "] Failed acquiring advisory lock", e); } } @@ -178,7 +174,7 @@ private List loadManifest() { plugin.getLogger().warning("[Migration:" + instanceScope + "] Failed to read manifest: " + e.getMessage()); } - migrations.sort(Comparator.comparingInt(m -> m.version)); + migrations.sort(Comparator.comparingInt(MigrationFile::version)); return migrations; } @@ -193,26 +189,26 @@ private boolean tableExists(DatabaseConnection conn, String tableName) { } private int getCurrentVersion(DatabaseConnection conn) throws SQLException { - try { - CompiledStatement stmt = conn.compileStatement( - "SELECT COALESCE(MAX(version), 0) FROM " + SCHEMA_TABLE + " WHERE scope = ?", - StatementBuilder.StatementType.SELECT, null, - DatabaseConnection.DEFAULT_RESULT_FLAGS, false); - try { - stmt.setObject(0, instanceScope, SqlType.STRING); - DatabaseResults results = stmt.runQuery(null); - try { - if (results.next()) { - return results.getInt(0); - } - } finally { - closeQuietly(results); + try (CompiledStatement stmt = conn.compileStatement( + "SELECT COALESCE(MAX(version), 0) FROM " + SCHEMA_TABLE + " WHERE scope = ?", + StatementBuilder.StatementType.SELECT, null, + DatabaseConnection.DEFAULT_RESULT_FLAGS, false)) { + stmt.setObject(0, instanceScope, SqlType.STRING); + try (DatabaseResults results = stmt.runQuery(null)) { + if (results.next()) { + return results.getInt(0); } - } finally { - closeQuietly(stmt); } } catch (SQLException e) { - // Table may not exist yet + // The schema_version table is created above via TableUtils.createTableIfNotExists, + // so an SQLException here usually indicates a real failure (permissions, deadlock, + // wrong scope value, etc.) rather than a missing table. Log it so the operator can + // diagnose, then fall through to 0 so we re-baseline rather than silently no-op. + plugin.getLogger().warning("[Migration:" + instanceScope + + "] Failed to read schema_version, treating as baseline V0", e); + } catch (Exception e) { + plugin.getLogger().warning("[Migration:" + instanceScope + + "] Unexpected error reading schema_version, treating as baseline V0", e); } return 0; } @@ -226,8 +222,7 @@ private String loadSqlFile(String filename) { return ""; } - byte[] bytes = readAllBytes(is); - return new String(bytes, StandardCharsets.UTF_8); + return new String(is.readAllBytes(), StandardCharsets.UTF_8); } catch (IOException e) { plugin.getLogger().warning("[Migration:" + instanceScope + "] Failed to read SQL file: " + path); return ""; @@ -334,67 +329,20 @@ static List splitStatements(String sql) { private void insertVersion(DatabaseConnection conn, int version, String description) throws SQLException { long appliedAt = System.currentTimeMillis() / 1000L; - CompiledStatement stmt = conn.compileStatement( + try (CompiledStatement stmt = conn.compileStatement( "INSERT INTO " + SCHEMA_TABLE + " (version, description, appliedAt, scope) VALUES (?, ?, ?, ?)", StatementBuilder.StatementType.UPDATE, null, - DatabaseConnection.DEFAULT_RESULT_FLAGS, false); - try { + DatabaseConnection.DEFAULT_RESULT_FLAGS, false)) { stmt.setObject(0, version, SqlType.INTEGER); stmt.setObject(1, description, SqlType.STRING); stmt.setObject(2, appliedAt, SqlType.LONG); stmt.setObject(3, instanceScope, SqlType.STRING); stmt.runUpdate(); - } finally { - closeQuietly(stmt); + } catch (Exception e) { + throw StorageUtils.toSqlException("[Migration:" + instanceScope + "] Failed inserting schema version", e); } } - private static void closeQuietly(CompiledStatement stmt) { - if (stmt != null) { - try { stmt.close(); } catch (IOException ignored) { } - } - } - - private static void closeQuietly(DatabaseResults results) { - if (results != null) { - try { results.close(); } catch (IOException ignored) { } - } - } - - private static byte[] readAllBytes(InputStream is) throws IOException { - byte[] buffer = new byte[4096]; - int bytesRead; - List chunks = new ArrayList<>(); - int totalLen = 0; - - while ((bytesRead = is.read(buffer)) != -1) { - byte[] chunk = new byte[bytesRead]; - System.arraycopy(buffer, 0, chunk, 0, bytesRead); - chunks.add(chunk); - totalLen += bytesRead; - } - - byte[] result = new byte[totalLen]; - int offset = 0; - for (byte[] chunk : chunks) { - System.arraycopy(chunk, 0, result, offset, chunk.length); - offset += chunk.length; - } - - return result; - } - - static class MigrationFile { - final String filename; - final int version; - final String description; - final boolean lenient; - - MigrationFile(String filename, int version, String description, boolean lenient) { - this.filename = filename; - this.version = version; - this.description = description; - this.lenient = lenient; - } + record MigrationFile(String filename, int version, String description, boolean lenient) { } } diff --git a/common/src/main/java/me/confuser/banmanager/common/storage/mysql/MySQLDatabase.java b/common/src/main/java/me/confuser/banmanager/common/storage/mysql/MySQLDatabase.java index 968092e9f..0e46da9b5 100644 --- a/common/src/main/java/me/confuser/banmanager/common/storage/mysql/MySQLDatabase.java +++ b/common/src/main/java/me/confuser/banmanager/common/storage/mysql/MySQLDatabase.java @@ -1,6 +1,6 @@ package me.confuser.banmanager.common.storage.mysql; -import me.confuser.banmanager.common.ormlite.db.MysqlDatabaseType; +import me.confuser.banmanager.common.ormlite.jdbc.db.MysqlDatabaseType; public class MySQLDatabase extends MysqlDatabaseType { @@ -11,7 +11,7 @@ public MySQLDatabase() { } @Override - protected String getDriverClassName() { - return DRIVER_CLASS_NAME; + protected String[] getDriverClassNames() { + return new String[] { DRIVER_CLASS_NAME }; } } diff --git a/common/src/main/java/me/confuser/banmanager/common/util/DateUtils.java b/common/src/main/java/me/confuser/banmanager/common/util/DateUtils.java index 7a3e32911..20321fa9b 100644 --- a/common/src/main/java/me/confuser/banmanager/common/util/DateUtils.java +++ b/common/src/main/java/me/confuser/banmanager/common/util/DateUtils.java @@ -11,7 +11,7 @@ public class DateUtils { - private static final List times = Arrays.asList( + private static final List times = List.of( Calendar.YEAR, Calendar.MONTH, Calendar.WEEK_OF_MONTH, @@ -19,10 +19,10 @@ public class DateUtils { Calendar.HOUR_OF_DAY, Calendar.MINUTE, Calendar.SECOND); - private static final List timesString = Arrays - .asList("year", "month", "week", "day", "hour", "minute", "second"); - private static final List shortTimesString = Arrays - .asList("y", "mo", "w", "d", "h", "m", "s"); + private static final List timesString = List.of( + "year", "month", "week", "day", "hour", "minute", "second"); + private static final List shortTimesString = List.of( + "y", "mo", "w", "d", "h", "m", "s"); @Getter private static long timeDiff = 0; private static Pattern timePattern = Pattern diff --git a/common/src/main/java/me/confuser/banmanager/common/util/MessageRegistry.java b/common/src/main/java/me/confuser/banmanager/common/util/MessageRegistry.java index 341946a65..bfc32fe15 100644 --- a/common/src/main/java/me/confuser/banmanager/common/util/MessageRegistry.java +++ b/common/src/main/java/me/confuser/banmanager/common/util/MessageRegistry.java @@ -4,14 +4,7 @@ public class MessageRegistry { - private static final class Snapshot { - final String defaultLocale; - final Map> locales; - - Snapshot(String defaultLocale, Map> locales) { - this.defaultLocale = defaultLocale; - this.locales = locales; - } + private record Snapshot(String defaultLocale, Map> locales) { } private volatile Snapshot snapshot; @@ -26,33 +19,33 @@ public static String normaliseLocale(String locale) { } public String getDefaultLocale() { - return snapshot.defaultLocale; + return snapshot.defaultLocale(); } public void loadLocale(String locale, Map messages) { String normalised = normaliseLocale(locale); Snapshot s = this.snapshot; - Map> copy = new HashMap<>(s.locales); - copy.put(normalised, Collections.unmodifiableMap(new HashMap<>(messages))); - this.snapshot = new Snapshot(s.defaultLocale, copy); + Map> copy = new HashMap<>(s.locales()); + copy.put(normalised, Map.copyOf(messages)); + this.snapshot = new Snapshot(s.defaultLocale(), copy); } public String getMessage(String key, String locale) { String normalised = normaliseLocale(locale); Snapshot s = this.snapshot; - String value = getFromLocale(s.locales, key, normalised); + String value = getFromLocale(s.locales(), key, normalised); if (value != null) return value; int underscore = normalised.indexOf('_'); if (underscore > 0) { String baseLanguage = normalised.substring(0, underscore); - value = getFromLocale(s.locales, key, baseLanguage); + value = getFromLocale(s.locales(), key, baseLanguage); if (value != null) return value; } - if (!normalised.equals(s.defaultLocale)) { - value = getFromLocale(s.locales, key, s.defaultLocale); + if (!normalised.equals(s.defaultLocale())) { + value = getFromLocale(s.locales(), key, s.defaultLocale()); if (value != null) return value; } @@ -60,17 +53,17 @@ public String getMessage(String key, String locale) { } public String getMessage(String key) { - return getMessage(key, snapshot.defaultLocale); + return getMessage(key, snapshot.defaultLocale()); } public void putMessage(String key, String message) { - putMessage(key, message, snapshot.defaultLocale); + putMessage(key, message, snapshot.defaultLocale()); } public void putMessage(String key, String message, String locale) { String normalised = normaliseLocale(locale); Snapshot s = this.snapshot; - Map> copy = new HashMap<>(s.locales); + Map> copy = new HashMap<>(s.locales()); Map localeMessages = copy.get(normalised); if (localeMessages == null) { @@ -80,29 +73,29 @@ public void putMessage(String key, String message, String locale) { } localeMessages.put(key, message); - copy.put(normalised, Collections.unmodifiableMap(localeMessages)); - this.snapshot = new Snapshot(s.defaultLocale, copy); + copy.put(normalised, Map.copyOf(localeMessages)); + this.snapshot = new Snapshot(s.defaultLocale(), copy); } public Set getAvailableLocales() { - return Collections.unmodifiableSet(new HashSet<>(snapshot.locales.keySet())); + return Set.copyOf(snapshot.locales().keySet()); } public Set getKeys(String locale) { - Map localeMessages = snapshot.locales.get(normaliseLocale(locale)); + Map localeMessages = snapshot.locales().get(normaliseLocale(locale)); if (localeMessages == null) return Collections.emptySet(); return Collections.unmodifiableSet(localeMessages.keySet()); } public Map getMessages(String locale) { - Map localeMessages = snapshot.locales.get(normaliseLocale(locale)); + Map localeMessages = snapshot.locales().get(normaliseLocale(locale)); if (localeMessages == null) return Collections.emptyMap(); return localeMessages; } public boolean hasAnyMessages() { Snapshot s = this.snapshot; - for (Map msgs : s.locales.values()) { + for (Map msgs : s.locales().values()) { if (!msgs.isEmpty()) return true; } return false; @@ -110,7 +103,7 @@ public boolean hasAnyMessages() { public int getMissingKeyCount(String locale) { Snapshot s = this.snapshot; - Set defaultKeys = getKeysFromSnapshot(s, s.defaultLocale); + Set defaultKeys = getKeysFromSnapshot(s, s.defaultLocale()); Set localeKeys = getKeysFromSnapshot(s, normaliseLocale(locale)); int missing = 0; @@ -126,7 +119,7 @@ public void atomicSwap(MessageRegistry newRegistry) { } private static Set getKeysFromSnapshot(Snapshot s, String locale) { - Map messages = s.locales.get(locale); + Map messages = s.locales().get(locale); if (messages == null) return Collections.emptySet(); return messages.keySet(); } diff --git a/common/src/main/java/me/confuser/banmanager/common/util/StorageUtils.java b/common/src/main/java/me/confuser/banmanager/common/util/StorageUtils.java index 7b42786cb..c14a8fbcc 100644 --- a/common/src/main/java/me/confuser/banmanager/common/util/StorageUtils.java +++ b/common/src/main/java/me/confuser/banmanager/common/util/StorageUtils.java @@ -8,11 +8,31 @@ import me.confuser.banmanager.common.ormlite.support.ConnectionSource; import me.confuser.banmanager.common.ormlite.support.DatabaseConnection; -import java.io.IOException; import java.sql.SQLException; public class StorageUtils { + /** + * Wraps an arbitrary exception as a {@link SQLException} for callers that + * declare {@code throws SQLException}. Returns the original instance when + * already a SQLException so the original message and stack trace are + * preserved; otherwise wraps with the supplied context message. + * + *

Callers should use the {@code throw} keyword:

+ *
+   *   try (CompiledStatement stmt = ...) { ... }
+   *   catch (Exception e) { throw StorageUtils.toSqlException("Context", e); }
+   * 
+ * + *

This pattern exists because ORMLite 6.x's {@code AutoCloseable} + * declarations throw the broader {@code Exception}, forcing every + * try-with-resources around a statement to also catch {@code Exception}.

+ */ + public static SQLException toSqlException(String message, Exception e) { + if (e instanceof SQLException sqle) return sqle; + return new SQLException(message, e); + } + /** * Updates the created and updated timestamps to database time using the DAO. * This ensures timestamps are always from the database, not the JVM, for cross-server sync. @@ -54,8 +74,8 @@ public static void updateTimestampsToDbTime(ConnectionSource connectionSource, D null, DatabaseConnection.DEFAULT_RESULT_FLAGS, false); statement.setObject(0, id, SqlType.INTEGER); statement.runUpdate(); - } catch (IOException e) { - throw new SQLException("Failed to update timestamps", e); + } catch (Exception e) { + throw toSqlException("Failed to update timestamps", e); } } diff --git a/common/src/main/java/me/confuser/banmanager/common/util/UUIDUtils.java b/common/src/main/java/me/confuser/banmanager/common/util/UUIDUtils.java index 0a2cdaa13..e54221ff7 100644 --- a/common/src/main/java/me/confuser/banmanager/common/util/UUIDUtils.java +++ b/common/src/main/java/me/confuser/banmanager/common/util/UUIDUtils.java @@ -1,10 +1,12 @@ package me.confuser.banmanager.common.util; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; -import java.net.URL; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.time.Duration; import java.util.UUID; import me.confuser.banmanager.common.BanManagerPlugin; @@ -16,16 +18,14 @@ * Based on UUIDFetcher by evilmidget38 */ public class UUIDUtils { - private static HttpURLConnection createConnection(String urlStr, String method) throws Exception { - URL url = new URL(urlStr); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod(method); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setUseCaches(false); - connection.setDoInput(true); - - if (method.equals("POST")) connection.setDoOutput(true); - return connection; + private static HttpRequest buildGet(String urlStr) { + return HttpRequest.newBuilder() + .uri(URI.create(urlStr)) + .timeout(Duration.ofSeconds(15)) + .header("Content-Type", "application/json") + .header("User-Agent", "BanManager") + .GET() + .build(); } private static UUID getUUID(String id) { @@ -58,55 +58,41 @@ public static UUIDProfile getUUIDOf(BanManagerPlugin plugin, String name) throws } plugin.getLogger().info("Requesting UUID for " + name); - Fetcher fetcher = plugin.getConfig().getUuidFetcher().getNameToId(); - String url = fetcher.getUrl().replace("[name]", name); + Fetcher fetcher = plugin.getConfig().getUuidFetcher().nameToId(); + String url = fetcher.url().replace("[name]", name); - HttpURLConnection connection = createConnection(url, "GET"); + HttpResponse response = sendBlocking(plugin.getHttpClient(), buildGet(url)); + int status = response.statusCode(); - try { - int status = connection.getResponseCode(); + plugin.getLogger().info(url + " " + status); - plugin.getLogger().info(url + " " + status); + if (status != 200) throw new Exception("Error retrieving UUID from " + url); - if (status != 200) throw new Exception("Error retrieving UUID from " + url); - - try (InputStreamReader reader = new InputStreamReader(connection.getInputStream())) { - JsonObject data = new Gson().fromJson(reader, JsonObject.class); - return new UUIDProfile(name, UUIDUtils.getUUID(data.get(fetcher.getKey()).getAsString())); - } - } finally { - connection.disconnect(); - } + JsonObject data = new Gson().fromJson(response.body(), JsonObject.class); + return new UUIDProfile(name, UUIDUtils.getUUID(data.get(fetcher.key()).getAsString())); } public static String getCurrentName(BanManagerPlugin plugin, UUID uuid) throws Exception { plugin.getLogger().info("Requesting name for " + uuid.toString()); - Fetcher fetcher = plugin.getConfig().getUuidFetcher().getIdToName(); - String url = fetcher.getUrl().replace("[uuid]", uuid.toString()); + Fetcher fetcher = plugin.getConfig().getUuidFetcher().idToName(); + String url = fetcher.url().replace("[uuid]", uuid.toString()); - HttpURLConnection connection = createConnection(url, "GET"); + HttpResponse response = sendBlocking(plugin.getHttpClient(), buildGet(url)); + int status = response.statusCode(); - try { - int status = connection.getResponseCode(); + plugin.getLogger().info(url + " " + status); - plugin.getLogger().info(url + " " + status); + if (status != 200) throw new Exception("Error retrieving name from " + url); - if (status != 200) throw new Exception("Error retrieving name from " + url); - - try (InputStreamReader reader = new InputStreamReader(connection.getInputStream())) { - JsonObject data = new Gson().fromJson(reader, JsonObject.class); - return data.get(fetcher.getKey()).getAsString(); - } - } finally { - connection.disconnect(); - } + JsonObject data = new Gson().fromJson(response.body(), JsonObject.class); + return data.get(fetcher.key()).getAsString(); } public static UUID createOfflineUUID(String name) { - try { - return UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes("UTF-8")); - } catch (UnsupportedEncodingException e) { - return null; - } + return UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8)); + } + + private static HttpResponse sendBlocking(HttpClient client, HttpRequest request) throws Exception { + return client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); } } diff --git a/common/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider b/common/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider new file mode 100644 index 000000000..0d1832d1c --- /dev/null +++ b/common/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider @@ -0,0 +1 @@ +org.slf4j.impl.BanManagerSlf4jServiceProvider diff --git a/common/src/test/java/me/confuser/banmanager/common/BasePluginDbTest.java b/common/src/test/java/me/confuser/banmanager/common/BasePluginDbTest.java index 66a43460d..8caec5bd2 100644 --- a/common/src/test/java/me/confuser/banmanager/common/BasePluginDbTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/BasePluginDbTest.java @@ -2,9 +2,14 @@ import ch.vorburger.exec.ManagedProcessException; import ch.vorburger.mariadb4j.DB; -import com.github.javafaker.Faker; -import org.junit.*; -import org.junit.rules.TemporaryFolder; +import me.confuser.banmanager.common.commands.CommonCommand; +import net.datafaker.Faker; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.io.TempDir; import java.io.File; import java.nio.charset.StandardCharsets; @@ -15,8 +20,8 @@ import static org.mockito.Mockito.*; public abstract class BasePluginDbTest { - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @TempDir + public File temporaryFolder; protected static String storageType = System.getenv("STORAGE_TYPE") != null ? System.getenv("STORAGE_TYPE") : "h2"; protected BanManagerPlugin plugin; protected Faker faker = new Faker(); @@ -25,7 +30,7 @@ public abstract class BasePluginDbTest { private static boolean configSetup = false; private static DB db; - @BeforeClass + @BeforeAll public static void dbSetup() throws ManagedProcessException { if (storageType.equals("mariadb")) { db = DB.newEmbeddedDB(0); @@ -33,10 +38,10 @@ public static void dbSetup() throws ManagedProcessException { } } - @Before + @BeforeEach public void setup() throws Exception { CommonLogger logger = new TestLogger(); - plugin = new BanManagerPlugin(BasePluginTest.setupConfigs(temporaryFolder), logger, temporaryFolder.getRoot(), new TestScheduler(), server, new TestMetrics()); + plugin = new BanManagerPlugin(BasePluginTest.setupConfigs(temporaryFolder), logger, temporaryFolder, new TestScheduler(), server, new TestMetrics()); testUtils = new TestUtils(plugin, faker); server.enable(plugin); @@ -47,13 +52,11 @@ public void setup() throws Exception { } catch (Exception e) { } - // Clean up any resources from the initial enable before reconfiguring plugin.disable(); setupConfig(); - // Recreate plugin with updated config - plugin = new BanManagerPlugin(BasePluginTest.setupConfigs(temporaryFolder), logger, temporaryFolder.getRoot(), new TestScheduler(), server, new TestMetrics()); + plugin = new BanManagerPlugin(BasePluginTest.setupConfigs(temporaryFolder), logger, temporaryFolder, new TestScheduler(), server, new TestMetrics()); testUtils = new TestUtils(plugin, faker); server.enable(plugin); } @@ -61,16 +64,16 @@ public void setup() throws Exception { plugin.enable(); } - @After + @AfterEach public void cleanup() { if (plugin != null) { plugin.disable(); } } - @AfterClass + @AfterAll public static void teardown() { - configSetup = false; // Reset for next test class + configSetup = false; if (db == null) return; @@ -81,8 +84,28 @@ public static void teardown() { } } + /** + * Locates a registered command by name and returns it cast to the requested + * type, or skips the calling test (via {@link Assumptions#assumeTrue}) if + * the command is not registered on this platform/profile. + * + *

Use from a {@code @BeforeEach} setup method so the assumption short- + * circuits the entire test class rather than each test method having to + * repeat the check.

+ */ + @SuppressWarnings("unchecked") + protected T requireCommand(String name) { + for (CommonCommand command : plugin.getCommands()) { + if (command.getCommandName().equals(name)) { + return (T) command; + } + } + Assumptions.assumeTrue(false, name + " command is not registered, skipping test class"); + return null; + } + private void setupConfig() throws Exception { - Path configFile = new File(temporaryFolder.getRoot(), "config.yml").toPath(); + Path configFile = new File(temporaryFolder, "config.yml").toPath(); List lines = Files.readAllLines(configFile, StandardCharsets.UTF_8); lines.set(5, " storageType: " + storageType); lines.set(6, " host: localhost"); diff --git a/common/src/test/java/me/confuser/banmanager/common/BasePluginTest.java b/common/src/test/java/me/confuser/banmanager/common/BasePluginTest.java index 720924bc2..d3d17ff4e 100644 --- a/common/src/test/java/me/confuser/banmanager/common/BasePluginTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/BasePluginTest.java @@ -3,22 +3,21 @@ import me.confuser.banmanager.common.configs.PluginInfo; import me.confuser.banmanager.common.configuration.ConfigurationSection; import me.confuser.banmanager.common.configuration.file.YamlConfiguration; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.io.TempDir; import java.io.*; public abstract class BasePluginTest { - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @TempDir + public File temporaryFolder; protected BanManagerPlugin plugin; - @Before + @BeforeEach public void setup() { CommonLogger logger = new TestLogger(); - plugin = new BanManagerPlugin(setupConfigs(temporaryFolder), logger, temporaryFolder.getRoot(), new TestScheduler(), new TestServer(), new TestMetrics()); + plugin = new BanManagerPlugin(setupConfigs(temporaryFolder), logger, temporaryFolder, new TestScheduler(), new TestServer(), new TestMetrics()); try { plugin.enable(); @@ -26,14 +25,14 @@ public void setup() { } } - @After + @AfterEach public void cleanup() { if (plugin != null) { plugin.disable(); } } - public static PluginInfo setupConfigs(TemporaryFolder folder) { + public static PluginInfo setupConfigs(File folder) { String[] configs = new String[]{ "config.yml", "console.yml", @@ -47,7 +46,7 @@ public static PluginInfo setupConfigs(TemporaryFolder folder) { for (String name : configs) { try (InputStream in = BasePluginTest.class.getClassLoader().getResource(name).openStream(); - OutputStream out = new FileOutputStream(new File(folder.getRoot(), name))) { + OutputStream out = new FileOutputStream(new File(folder, name))) { byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { @@ -58,7 +57,7 @@ public static PluginInfo setupConfigs(TemporaryFolder folder) { } } - File messagesDir = new File(folder.getRoot(), "messages"); + File messagesDir = new File(folder, "messages"); messagesDir.mkdirs(); try (InputStream in = BasePluginTest.class.getClassLoader().getResource("messages/messages_en.yml").openStream(); OutputStream out = new FileOutputStream(new File(messagesDir, "messages_en.yml"))) { @@ -71,7 +70,6 @@ public static PluginInfo setupConfigs(TemporaryFolder folder) { e.printStackTrace(); } - // Load plugin.yml PluginInfo pluginInfo = new PluginInfo(); try (InputStream in = BasePluginTest.class.getClassLoader().getResource("plugin.yml").openStream(); Reader defConfigStream = new InputStreamReader(in)) { diff --git a/common/src/test/java/me/confuser/banmanager/common/CommonLoggerTest.java b/common/src/test/java/me/confuser/banmanager/common/CommonLoggerTest.java index 851540f80..ab59e70d9 100644 --- a/common/src/test/java/me/confuser/banmanager/common/CommonLoggerTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/CommonLoggerTest.java @@ -1,13 +1,13 @@ package me.confuser.banmanager.common; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class CommonLoggerTest { @@ -72,7 +72,7 @@ public void defaultMethodsShouldNotWriteToStderr() { logger.severe("test", new RuntimeException("err")); logger.warning("test", new RuntimeException("err")); - assertEquals("No output should go to stderr", 0, baos.size()); + assertEquals(0, baos.size(), "No output should go to stderr"); } finally { System.setErr(originalErr); } diff --git a/common/src/test/java/me/confuser/banmanager/common/PluginTest.java b/common/src/test/java/me/confuser/banmanager/common/PluginTest.java index c0700dfb9..ee84db845 100644 --- a/common/src/test/java/me/confuser/banmanager/common/PluginTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/PluginTest.java @@ -1,8 +1,8 @@ package me.confuser.banmanager.common; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class PluginTest extends BasePluginTest { @Test diff --git a/common/src/test/java/me/confuser/banmanager/common/StderrRegressionTest.java b/common/src/test/java/me/confuser/banmanager/common/StderrRegressionTest.java index b9356f1d5..2f1a88174 100644 --- a/common/src/test/java/me/confuser/banmanager/common/StderrRegressionTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/StderrRegressionTest.java @@ -1,13 +1,13 @@ package me.confuser.banmanager.common; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; import java.io.PrintStream; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Verifies that plugin startup does not write to System.err via @@ -18,7 +18,7 @@ public class StderrRegressionTest extends BasePluginDbTest { private PrintStream originalErr; private ByteArrayOutputStream errCapture; - @Before + @BeforeEach @Override public void setup() throws Exception { originalErr = System.err; @@ -28,7 +28,7 @@ public void setup() throws Exception { super.setup(); } - @After + @AfterEach @Override public void cleanup() { super.cleanup(); @@ -56,7 +56,7 @@ public void pluginStartupShouldNotWriteToStderr() { offendingLines.append(line).append("\n"); } } - assertEquals("No e.printStackTrace() output should appear during startup:\n" + offendingLines, 0, offendingLines.length()); + assertEquals(0, offendingLines.length(), "No e.printStackTrace() output should appear during startup:\n" + offendingLines); } } } diff --git a/common/src/test/java/me/confuser/banmanager/common/TestUtils.java b/common/src/test/java/me/confuser/banmanager/common/TestUtils.java index d6f35b1a0..9f9c07b2e 100644 --- a/common/src/test/java/me/confuser/banmanager/common/TestUtils.java +++ b/common/src/test/java/me/confuser/banmanager/common/TestUtils.java @@ -1,6 +1,6 @@ package me.confuser.banmanager.common; -import com.github.javafaker.Faker; +import net.datafaker.Faker; import lombok.AllArgsConstructor; import me.confuser.banmanager.common.data.PlayerBanData; import me.confuser.banmanager.common.data.PlayerData; @@ -35,7 +35,7 @@ public PlayerData createPlayerWithName(String name) { } public String createRandomPlayerName() { - String name = faker.name().username(); + String name = faker.credentials().username(); return name.substring(0, Math.min(name.length(), 16)); } diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/AddNoteCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/AddNoteCommandTest.java index bb8173bb8..a9b7d4dc0 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/AddNoteCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/AddNoteCommandTest.java @@ -3,19 +3,19 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.CommonServer; import me.confuser.banmanager.common.data.PlayerData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class AddNoteCommandTest extends BasePluginDbTest { private AddNoteCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("addnote")) { @@ -46,7 +46,7 @@ public void shouldFailIfPlayerNotFound() { @Test public void shouldAddNoteToPlayer() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "test note message"}; @@ -59,7 +59,7 @@ public void shouldAddNoteToPlayer() throws SQLException { @Test public void shouldAddNoteSilently() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "silent note", "-s"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/BanCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/BanCommandTest.java index fdc717d01..87bf75981 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/BanCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/BanCommandTest.java @@ -6,20 +6,20 @@ import me.confuser.banmanager.common.TestPlayer; import me.confuser.banmanager.common.data.PlayerBanData; import me.confuser.banmanager.common.data.PlayerData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import java.util.UUID; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class BanCommandTest extends BasePluginDbTest { private BanCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("ban")) { @@ -154,7 +154,7 @@ public void shouldAllowPartialWhenNoExactCollision() { @Test public void shouldFailIfExempt() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); CommonPlayer commonPlayer = spy(new TestPlayer(player.getUUID(), player.getName(), true)); this.server.setExactMatch(player.getName(), commonPlayer); @@ -179,7 +179,7 @@ public void shouldFailIfNotFound() { @Test public void shouldFailIfOfflineExempt() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); CommonPlayer commonPlayer = spy(new TestPlayer(player.getUUID(), player.getName(), true)); this.server.setExactMatch(player.getName(), commonPlayer); @@ -195,7 +195,7 @@ public void shouldFailIfOfflineExempt() { @Test public void shouldBanPlayer() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "test"}; @@ -213,7 +213,7 @@ public void shouldBanPlayer() { @Test public void shouldBanPlayerSilently() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "test", "-s"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/BanIpCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/BanIpCommandTest.java index 1e9a4ef9e..92c7e90b6 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/BanIpCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/BanIpCommandTest.java @@ -8,20 +8,20 @@ import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.ipaddr.IPAddress; import me.confuser.banmanager.common.util.IPUtils; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.*; public class BanIpCommandTest extends BasePluginDbTest { private BanIpCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("banip")) { @@ -76,7 +76,7 @@ public void shouldFailIfAlreadyBanned() throws SQLException { @Test public void shouldFailIfExempt() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); CommonPlayer commonPlayer = spy(server.getPlayer(player.getName())); String[] args = new String[]{player.getName(), "test"}; @@ -100,7 +100,7 @@ public void shouldFailIfNotFound() { @Test public void shouldFailIfOfflineExempt() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); ExemptionsConfig config = spy(plugin.getExemptionsConfig()); String[] args = new String[]{player.getName(), "test"}; @@ -115,7 +115,7 @@ public void shouldFailIfOfflineExempt() { @Test public void shouldBanIp() { IPAddress ip = IPUtils.toIPAddress(faker.internet().ipV6Address()); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{ip.toString(), "test"}; @@ -133,7 +133,7 @@ public void shouldBanIp() { @Test public void shouldBanIpSilently() { IPAddress ip = IPUtils.toIPAddress(faker.internet().ipV6Address()); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{ip.toString(), "test", "-s"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/BanIpRangeCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/BanIpRangeCommandTest.java index bd66dd42c..4e0e88330 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/BanIpRangeCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/BanIpRangeCommandTest.java @@ -7,21 +7,21 @@ import me.confuser.banmanager.common.ipaddr.IPAddressSeqRange; import me.confuser.banmanager.common.ipaddr.IPAddressString; import me.confuser.banmanager.common.util.IPUtils; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.mockito.Mockito.*; public class BanIpRangeCommandTest extends BasePluginDbTest { private BanIpRangeCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("baniprange")) { @@ -85,7 +85,7 @@ public void shouldBanRange() { IPAddress expectedFromIp = range.getLower(); IPAddress expectedToIp = range.getUpper(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{cidr, "test"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/BanNameCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/BanNameCommandTest.java index 020b30eba..196c868b1 100755 --- a/common/src/test/java/me/confuser/banmanager/common/commands/BanNameCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/BanNameCommandTest.java @@ -4,19 +4,19 @@ import me.confuser.banmanager.common.CommonServer; import me.confuser.banmanager.common.data.NameBanData; import me.confuser.banmanager.common.data.PlayerData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class BanNameCommandTest extends BasePluginDbTest { private BanNameCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("banname")) { @@ -62,7 +62,7 @@ public void shouldFailIfAlreadyBanned() throws SQLException { @Test public void shouldBanPlayerName() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "test"}; @@ -80,7 +80,7 @@ public void shouldBanPlayerName() { @Test public void shouldBanNameSilently() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "test", "-s"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/CommandParserTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/CommandParserTest.java index 6e8a381ca..3415951cf 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/CommandParserTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/CommandParserTest.java @@ -1,9 +1,9 @@ package me.confuser.banmanager.common.commands; import me.confuser.banmanager.common.BasePluginTest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class CommandParserTest extends BasePluginTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/InfoCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/InfoCommandTest.java index 972ed0b9d..0e4a4300e 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/InfoCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/InfoCommandTest.java @@ -4,19 +4,19 @@ import me.confuser.banmanager.common.CommonServer; import me.confuser.banmanager.common.data.*; import me.confuser.banmanager.common.util.parsers.InfoCommandParser; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class InfoCommandTest extends BasePluginDbTest { private InfoCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("bminfo")) { @@ -29,7 +29,7 @@ public void setupCmd() { @Test public void shouldShowPlayerInfo() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName()}; @@ -42,7 +42,7 @@ public void shouldShowPlayerInfo() { public void shouldShowBanHistory() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); PlayerData actor = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // Create a ban and unban to create history @@ -59,7 +59,7 @@ public void shouldShowBanHistory() throws SQLException { public void shouldShowMuteHistory() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); PlayerData actor = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // Create a mute and unmute to create history @@ -76,7 +76,7 @@ public void shouldShowMuteHistory() throws SQLException { public void shouldShowWarnings() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); PlayerData actor = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // Create a warning @@ -93,7 +93,7 @@ public void shouldShowWarnings() throws SQLException { public void shouldShowNotes() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); PlayerData actor = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // Create a note @@ -119,7 +119,7 @@ public void shouldFailIfPlayerNotFound() { @Test public void shouldShowKnownNames() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // Create a session record (which includes name) @@ -136,7 +136,7 @@ public void shouldShowKnownNames() throws SQLException { @Test public void shouldHideNamesWithoutPermission() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // Create a session record (which includes name) @@ -154,7 +154,7 @@ public void shouldHideNamesWithoutPermission() throws SQLException { public void shouldShowStatsWithMultipleRecordTypes() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); PlayerData actor = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); PlayerBanData ban = testUtils.createBan(player, actor, "test ban"); diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/KickAllCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/KickAllCommandTest.java index 3922ebfe6..b6836dddb 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/KickAllCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/KickAllCommandTest.java @@ -4,17 +4,17 @@ import me.confuser.banmanager.common.CommonPlayer; import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.util.Message; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class KickAllCommandTest extends BasePluginDbTest { private KickAllCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("kickall")) { diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/KickCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/KickCommandTest.java index d1222145b..f0cf5ff0a 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/KickCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/KickCommandTest.java @@ -4,17 +4,17 @@ import me.confuser.banmanager.common.CommonPlayer; import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.util.Message; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class KickCommandTest extends BasePluginDbTest { private KickCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("kick")) { diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/LoglessKickAllCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/LoglessKickAllCommandTest.java index 12bc88f54..a86391be5 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/LoglessKickAllCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/LoglessKickAllCommandTest.java @@ -4,17 +4,17 @@ import me.confuser.banmanager.common.CommonPlayer; import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.util.Message; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class LoglessKickAllCommandTest extends BasePluginDbTest { private LoglessKickAllCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("nlkickall")) { diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/MuteCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/MuteCommandTest.java index 496419ba7..e350aa59d 100755 --- a/common/src/test/java/me/confuser/banmanager/common/commands/MuteCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/MuteCommandTest.java @@ -6,20 +6,20 @@ import me.confuser.banmanager.common.TestPlayer; import me.confuser.banmanager.common.data.PlayerMuteData; import me.confuser.banmanager.common.data.PlayerData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import java.util.UUID; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class MuteCommandTest extends BasePluginDbTest { private MuteCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("mute")) { @@ -130,7 +130,7 @@ public void shouldAllowPartialWhenNoExactCollision() { @Test public void shouldFailIfExempt() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); CommonPlayer commonPlayer = spy(new TestPlayer(player.getUUID(), player.getName(), true)); this.server.setExactMatch(player.getName(), commonPlayer); @@ -155,7 +155,7 @@ public void shouldFailIfNotFound() { @Test public void shouldFailIfOfflineExempt() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); CommonPlayer commonPlayer = spy(new TestPlayer(player.getUUID(), player.getName(), true)); this.server.setExactMatch(player.getName(), commonPlayer); @@ -171,7 +171,7 @@ public void shouldFailIfOfflineExempt() { @Test public void shouldMutePlayer() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "test"}; @@ -189,7 +189,7 @@ public void shouldMutePlayer() { @Test public void shouldMutePlayerSoftly() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "test", "-st"}; @@ -208,7 +208,7 @@ public void shouldMutePlayerSoftly() { @Test public void shouldMutePlayerSilently() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "test", "-s"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/MuteIpCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/MuteIpCommandTest.java index ffec0bac0..ed1a158df 100755 --- a/common/src/test/java/me/confuser/banmanager/common/commands/MuteIpCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/MuteIpCommandTest.java @@ -8,19 +8,19 @@ import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.ipaddr.IPAddress; import me.confuser.banmanager.common.util.IPUtils; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class MuteIpCommandTest extends BasePluginDbTest { private MuteIpCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("muteip")) { @@ -75,7 +75,7 @@ public void shouldFailIfAlreadyBanned() throws SQLException { @Test public void shouldFailIfExempt() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); CommonPlayer commonPlayer = spy(server.getPlayer(player.getName())); String[] args = new String[]{player.getName(), "test"}; @@ -99,7 +99,7 @@ public void shouldFailIfNotFound() { @Test public void shouldFailIfOfflineExempt() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); ExemptionsConfig config = spy(plugin.getExemptionsConfig()); String[] args = new String[]{player.getName(), "test"}; @@ -114,7 +114,7 @@ public void shouldFailIfOfflineExempt() { @Test public void shouldMuteIp() { IPAddress ip = IPUtils.toIPAddress(faker.internet().ipV6Address()); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{ip.toString(), "test"}; @@ -132,7 +132,7 @@ public void shouldMuteIp() { @Test public void shouldMuteIpSilently() { IPAddress ip = IPUtils.toIPAddress(faker.internet().ipV6Address()); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{ip.toString(), "test", "-s"}; @@ -146,7 +146,7 @@ public void shouldMuteIpSilently() { @Test public void shouldMuteIpSoftly() { IPAddress ip = IPUtils.toIPAddress(faker.internet().ipV6Address()); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{ip.toString(), "test", "-st"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/NamesCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/NamesCommandTest.java index a89c51eb7..b7daab3db 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/NamesCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/NamesCommandTest.java @@ -2,8 +2,8 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.data.PlayerData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; @@ -13,7 +13,7 @@ public class NamesCommandTest extends BasePluginDbTest { private NamesCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("bmnames")) { diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/ReportCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/ReportCommandTest.java index d8ee7dfca..0e4df47f0 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/ReportCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/ReportCommandTest.java @@ -4,35 +4,28 @@ import me.confuser.banmanager.common.CommonServer; import me.confuser.banmanager.common.TestPlayer; import me.confuser.banmanager.common.data.PlayerData; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import java.util.UUID; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class ReportCommandTest extends BasePluginDbTest { private ReportCommand cmd; - @Before + @BeforeEach public void setupCmd() { - for (CommonCommand command : plugin.getCommands()) { - if (command.getCommandName().equals("report")) { - this.cmd = (ReportCommand) command; - break; - } - } + cmd = requireCommand("report"); } @Test public void shouldCreateReport() throws SQLException { - Assume.assumeNotNull(cmd); PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "test report reason"}; @@ -42,8 +35,7 @@ public void shouldCreateReport() throws SQLException { @Test public void shouldFailIfSelfReport() { - Assume.assumeNotNull(cmd); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // Get sender's player data @@ -56,7 +48,6 @@ public void shouldFailIfSelfReport() { @Test public void shouldFailIfPlayerNotFound() { - Assume.assumeNotNull(cmd); CommonSender sender = spy(plugin.getServer().getConsoleSender()); String playerName = testUtils.createRandomPlayerName(); String[] args = new String[]{playerName, "test report"}; @@ -67,7 +58,6 @@ public void shouldFailIfPlayerNotFound() { @Test public void shouldFailIfNoReasonGiven() { - Assume.assumeNotNull(cmd); CommonSender sender = plugin.getServer().getConsoleSender(); String[] args = new String[]{"confuser"}; @@ -121,9 +111,8 @@ public void shouldAllowPartialWhenNoExactCollision() throws SQLException { @Test public void shouldNotifyStaff() throws SQLException { - Assume.assumeNotNull(cmd); PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "test report notification"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/RollbackCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/RollbackCommandTest.java index 1db257eed..14d2076f6 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/RollbackCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/RollbackCommandTest.java @@ -3,19 +3,19 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.CommonServer; import me.confuser.banmanager.common.data.*; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class RollbackCommandTest extends BasePluginDbTest { private RollbackCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("bmrollback")) { @@ -65,7 +65,7 @@ public void shouldRollbackActiveBan() throws SQLException { assertTrue(plugin.getPlayerBanStorage().isBanned(victim.getUUID())); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{maliciousMod.getName(), "1d", "bans"}; @@ -107,7 +107,7 @@ public void shouldRollbackUnbanAndRestoreLegitBan() throws SQLException { .countOf(); assertEquals(1, recordCount); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{maliciousMod.getName(), "1d", "banrecords"}; @@ -156,7 +156,7 @@ public void shouldNotRestoreBanWhenBothActionsAreMalicious() throws SQLException .countOf(); assertEquals(1, recordCount); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{maliciousMod.getName(), "1d", "banrecords"}; @@ -200,7 +200,7 @@ public void shouldCleanupRecordsOfMaliciousBans() throws SQLException { .countOf(); assertEquals(1, recordCount); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // Rolling back banrecords for malicious mod should clean up records where they were the original banner String[] args = new String[]{maliciousMod.getName(), "1d", "banrecords"}; @@ -242,7 +242,7 @@ public void shouldNotAffectBansOutsideTimeframe() throws SQLException, Interrupt // Wait a bit to ensure time difference Thread.sleep(100); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // Rollback only last 1 second (ban was created more than 1 second ago) String[] args = new String[]{maliciousMod.getName(), "1s", "bans"}; @@ -269,7 +269,7 @@ public void shouldRollbackMutes() throws SQLException { assertTrue(plugin.getPlayerMuteStorage().isMuted(victim.getUUID())); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{maliciousMod.getName(), "1d", "mutes"}; @@ -304,7 +304,7 @@ public void shouldRollbackMuteRecordsAndRestoreLegitMute() throws SQLException { testUtils.unmutePlayer(mute, maliciousMod); assertFalse(plugin.getPlayerMuteStorage().isMuted(victim.getUUID())); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{maliciousMod.getName(), "1d", "muterecords"}; @@ -347,7 +347,7 @@ public void shouldNotRestoreMuteWhenBothActionsAreMalicious() throws SQLExceptio .countOf(); assertEquals(1, recordCount); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{maliciousMod.getName(), "1d", "muterecords"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/TabCompletionTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/TabCompletionTest.java index 5b2792448..1f88d4264 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/TabCompletionTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/TabCompletionTest.java @@ -3,18 +3,18 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.CommonPlayer; import me.confuser.banmanager.common.data.PlayerData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class TabCompletionTest extends BasePluginDbTest { private CommonCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand command : plugin.getCommands()) { if (command.getCommandName().equals("ban")) { @@ -36,9 +36,9 @@ public void shouldCompletePlayerNameFromStart() { List suggestions = cmd.handlePlayerNameTabComplete(sender, args); - assertTrue("Should suggest TestPlayer1", suggestions.contains("TestPlayer1")); - assertTrue("Should suggest TestPlayer2", suggestions.contains("TestPlayer2")); - assertFalse("Should not suggest OtherPlayer", suggestions.contains("OtherPlayer")); + assertTrue(suggestions.contains("TestPlayer1"), "Should suggest TestPlayer1"); + assertTrue(suggestions.contains("TestPlayer2"), "Should suggest TestPlayer2"); + assertFalse(suggestions.contains("OtherPlayer"), "Should not suggest OtherPlayer"); } @Test @@ -51,9 +51,9 @@ public void shouldCompleteEmptyArg() { List suggestions = cmd.handlePlayerNameTabComplete(sender, args); - assertTrue("Should include all players for empty input", suggestions.size() >= 2); - assertTrue("Should suggest Alpha", suggestions.contains("Alpha")); - assertTrue("Should suggest Beta", suggestions.contains("Beta")); + assertTrue(suggestions.size() >= 2, "Should include all players for empty input"); + assertTrue(suggestions.contains("Alpha"), "Should suggest Alpha"); + assertTrue(suggestions.contains("Beta"), "Should suggest Beta"); } @Test @@ -69,8 +69,8 @@ public void shouldCompleteMultiplePlayersWithComma() { List suggestions = cmd.handlePlayerNameTabComplete(sender, args); // Should complete with the full prefix including first player - assertTrue("Should suggest Alice,Alice", suggestions.stream().anyMatch(s -> s.startsWith("Alice,Alice"))); - assertTrue("Should suggest Alice,AliceAlt", suggestions.stream().anyMatch(s -> s.startsWith("Alice,AliceAlt"))); + assertTrue(suggestions.stream().anyMatch(s -> s.startsWith("Alice,Alice")), "Should suggest Alice,Alice"); + assertTrue(suggestions.stream().anyMatch(s -> s.startsWith("Alice,AliceAlt")), "Should suggest Alice,AliceAlt"); } @Test @@ -91,7 +91,7 @@ public void shouldReturnEmptyForDisabledTabCompletion() { String[] args = new String[]{"Test"}; List suggestions = noTabCmd.handlePlayerNameTabComplete(sender, args); - assertTrue("Should return empty list for disabled tab completion", suggestions.isEmpty()); + assertTrue(suggestions.isEmpty(), "Should return empty list for disabled tab completion"); } @Test @@ -106,7 +106,7 @@ public void shouldLimitResultsTo100() { List suggestions = cmd.handlePlayerNameTabComplete(sender, args); - assertTrue("Should limit results to 100 or less", suggestions.size() <= 100); + assertTrue(suggestions.size() <= 100, "Should limit results to 100 or less"); } @Test @@ -126,7 +126,7 @@ public void shouldBeCaseInsensitiveForOnlinePlayers() { // Offline auto-complete is case-sensitive by design (uses radix tree) // So this should not find CaseSensitive when searching for "casesens" // But let's verify behavior is consistent - assertNotNull("Should return a list", suggestions); + assertNotNull(suggestions, "Should return a list"); } @Test @@ -139,6 +139,6 @@ public void shouldNotSuggestForSecondArgWithoutHashtag() { List suggestions = cmd.handlePlayerNameTabComplete(sender, args); - assertTrue("Should return empty for non-hashtag second arg", suggestions.isEmpty()); + assertTrue(suggestions.isEmpty(), "Should return empty for non-hashtag second arg"); } } diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/TempBanCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/TempBanCommandTest.java index 55ee5b112..e549ee01d 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/TempBanCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/TempBanCommandTest.java @@ -6,20 +6,20 @@ import me.confuser.banmanager.common.TestPlayer; import me.confuser.banmanager.common.data.PlayerBanData; import me.confuser.banmanager.common.data.PlayerData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import java.util.UUID; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class TempBanCommandTest extends BasePluginDbTest { private TempBanCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("tempban")) { @@ -130,7 +130,7 @@ public void shouldAllowPartialWhenNoExactCollision() { @Test public void shouldFailIfExempt() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); CommonPlayer commonPlayer = spy(new TestPlayer(player.getUUID(), player.getName(), true)); this.server.setExactMatch(player.getName(), commonPlayer); @@ -155,7 +155,7 @@ public void shouldFailIfNotFound() { @Test public void shouldFailIfOfflineExempt() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); CommonPlayer commonPlayer = spy(new TestPlayer(player.getUUID(), player.getName(), true)); this.server.setExactMatch(player.getName(), commonPlayer); @@ -171,7 +171,7 @@ public void shouldFailIfOfflineExempt() { @Test public void shouldBanPlayer() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "30y", "test"}; @@ -189,7 +189,7 @@ public void shouldBanPlayer() { @Test public void shouldBanPlayerSilently() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "30y", "test", "-s"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/TempMuteCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/TempMuteCommandTest.java index 6ea1a58ca..124311dd2 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/TempMuteCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/TempMuteCommandTest.java @@ -5,20 +5,20 @@ import me.confuser.banmanager.common.TestPlayer; import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.data.PlayerMuteData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import java.util.UUID; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class TempMuteCommandTest extends BasePluginDbTest { private TempMuteCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("tempmute")) { @@ -48,7 +48,7 @@ public void shouldFailIfInvalidTimeFormat() { @Test public void shouldTempMutePlayer() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "1h", "test"}; @@ -75,7 +75,7 @@ public void shouldTempMuteWithVariousTimeFormats() { await().until(() -> plugin.getPlayerMuteStorage().isMuted(player.getUUID())); PlayerMuteData mute = plugin.getPlayerMuteStorage().getMute(player.getUUID()); - assertTrue("Expiry should be set for " + time, mute.getExpires() > 0); + assertTrue(mute.getExpires() > 0, "Expiry should be set for " + time); // Clean up plugin.getPlayerMuteStorage().removeMute(player.getUUID()); @@ -86,7 +86,7 @@ public void shouldTempMuteWithVariousTimeFormats() { public void shouldTempMuteWithLongDuration() { // Test that very long durations are accepted when time limits are not configured PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "30y", "test"}; @@ -99,7 +99,7 @@ public void shouldTempMuteWithLongDuration() { @Test public void shouldFailWhenAlreadyMutedWithoutOverride() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // First mute the player @@ -122,7 +122,7 @@ public void shouldFailWhenAlreadyMutedWithoutOverride() throws SQLException { @Test public void shouldTempMuteSilently() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "1h", "test", "-s"}; @@ -136,7 +136,7 @@ public void shouldTempMuteSilently() { @Test public void shouldTempMuteSoftly() { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "1h", "test", "-st"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/TempWarnCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/TempWarnCommandTest.java index 903361778..a2ed0ca0c 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/TempWarnCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/TempWarnCommandTest.java @@ -6,20 +6,20 @@ import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.data.PlayerWarnData; import me.confuser.banmanager.common.util.parsers.WarnCommandParser; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import java.util.UUID; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class TempWarnCommandTest extends BasePluginDbTest { private TempWarnCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("tempwarn")) { @@ -32,7 +32,7 @@ public void setupCmd() { @Test public void shouldTempWarnPlayer() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "1h", "test warning"}; @@ -48,7 +48,7 @@ public void shouldTempWarnPlayer() throws SQLException { @Test public void shouldTempWarnWithPoints() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{"-p", "5", player.getName(), "1h", "test warning"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/UnbanCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/UnbanCommandTest.java index 75397a2f1..88c873746 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/UnbanCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/UnbanCommandTest.java @@ -5,20 +5,20 @@ import me.confuser.banmanager.common.data.PlayerBanData; import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.util.parsers.UnbanCommandParser; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import java.util.UUID; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class UnbanCommandTest extends BasePluginDbTest { private UnbanCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("unban")) { @@ -61,7 +61,7 @@ public void shouldFailIfInvalidUUID() { @Test public void shouldUnbanPlayer() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // First ban the player @@ -81,7 +81,7 @@ public void shouldUnbanPlayer() throws SQLException { @Test public void shouldUnbanByUUID() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); PlayerBanData ban = testUtils.createBan(player, sender.getData(), "test ban"); @@ -97,7 +97,7 @@ public void shouldUnbanByUUID() throws SQLException { @Test public void shouldUnbanWithDeleteFlag() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); when(sender.hasPermission(cmd.getPermission() + ".delete")).thenReturn(true); @@ -117,7 +117,7 @@ public void shouldUnbanWithDeleteFlag() throws SQLException { @Test public void shouldFailDeleteWithoutPermission() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); when(sender.hasPermission(cmd.getPermission() + ".delete")).thenReturn(false); @@ -135,7 +135,7 @@ public void shouldFailDeleteWithoutPermission() throws SQLException { @Test public void shouldUnbanSilently() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); PlayerBanData ban = testUtils.createBan(player, sender.getData(), "test ban"); @@ -154,7 +154,7 @@ public void shouldUnbanSilently() throws SQLException { public void shouldFailOwnUnbanWithoutPermission() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); PlayerData otherMod = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // Create ban by a different actor diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/UnmuteCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/UnmuteCommandTest.java index 4a5b91fea..4820d4bea 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/UnmuteCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/UnmuteCommandTest.java @@ -5,19 +5,19 @@ import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.data.PlayerMuteData; import me.confuser.banmanager.common.util.parsers.UnbanCommandParser; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class UnmuteCommandTest extends BasePluginDbTest { private UnmuteCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("unmute")) { @@ -50,7 +50,7 @@ public void shouldFailIfPlayerNotFound() { @Test public void shouldUnmutePlayer() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // First mute the player @@ -70,7 +70,7 @@ public void shouldUnmutePlayer() throws SQLException { @Test public void shouldUnmuteByUUID() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); PlayerMuteData mute = testUtils.createMute(player, sender.getData(), "test mute"); @@ -86,7 +86,7 @@ public void shouldUnmuteByUUID() throws SQLException { @Test public void shouldUnmuteWithDeleteFlag() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); when(sender.hasPermission(cmd.getPermission() + ".delete")).thenReturn(true); @@ -106,7 +106,7 @@ public void shouldUnmuteWithDeleteFlag() throws SQLException { @Test public void shouldFailDeleteWithoutPermission() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); when(sender.hasPermission(cmd.getPermission() + ".delete")).thenReturn(false); @@ -124,7 +124,7 @@ public void shouldFailDeleteWithoutPermission() throws SQLException { @Test public void shouldUnmuteSilently() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); PlayerMuteData mute = testUtils.createMute(player, sender.getData(), "test mute"); @@ -143,7 +143,7 @@ public void shouldUnmuteSilently() throws SQLException { public void shouldFailOwnUnmuteWithoutPermission() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); PlayerData otherMod = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); // Create mute by a different actor diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/WarnCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/WarnCommandTest.java index 86665461a..7386fb85d 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/WarnCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/WarnCommandTest.java @@ -10,8 +10,8 @@ import me.confuser.banmanager.common.data.PlayerWarnData; import me.confuser.banmanager.common.util.DateUtils; import me.confuser.banmanager.common.util.parsers.WarnCommandParser; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import java.util.Arrays; @@ -20,7 +20,7 @@ import java.util.List; import java.util.UUID; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.*; @@ -30,7 +30,7 @@ public class WarnCommandTest extends BasePluginDbTest { private WarnCommand cmd; - @Before + @BeforeEach public void setupCmd() { for (CommonCommand cmd : plugin.getCommands()) { if (cmd.getCommandName().equals("warn")) { @@ -145,7 +145,7 @@ public void shouldFailIfPlayerExempt() { @Test public void shouldWarnPlayer() throws SQLException { PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "test"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/global/BanAllCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/global/BanAllCommandTest.java index a167a8cb7..e7393123d 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/global/BanAllCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/global/BanAllCommandTest.java @@ -3,49 +3,39 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.CommonServer; import me.confuser.banmanager.common.commands.CommandParser; -import me.confuser.banmanager.common.commands.CommonCommand; import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.PlayerData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; -import org.junit.Assume; public class BanAllCommandTest extends BasePluginDbTest { private BanAllCommand cmd; - @Before + @BeforeEach public void setupCmd() { - for (CommonCommand command : plugin.getCommands()) { - if (command.getCommandName().equals("banall")) { - this.cmd = (BanAllCommand) command; - break; - } - } + cmd = requireCommand("banall"); } @Test public void shouldCreateGlobalBan() throws SQLException { - Assume.assumeNotNull(cmd); PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "global ban test"}; assert (cmd.onCommand(sender, new CommandParser(plugin, args, 1))); - // Verify the command was executed (the global ban was created) await().untilAsserted(() -> verify(sender, atLeastOnce()).sendMessage(anyString())); } @Test public void shouldFailIfNoReasonGiven() { - Assume.assumeNotNull(cmd); CommonSender sender = plugin.getServer().getConsoleSender(); String[] args = new String[]{"confuser"}; @@ -54,7 +44,6 @@ public void shouldFailIfNoReasonGiven() { @Test public void shouldFailIfPlayerNotFound() { - Assume.assumeNotNull(cmd); CommonSender sender = spy(plugin.getServer().getConsoleSender()); String playerName = testUtils.createRandomPlayerName(); String[] args = new String[]{playerName, "test"}; @@ -65,9 +54,8 @@ public void shouldFailIfPlayerNotFound() { @Test public void shouldNotifyOnGlobalBan() throws SQLException { - Assume.assumeNotNull(cmd); PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "global ban notification test"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/global/MuteAllCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/global/MuteAllCommandTest.java index b0062e468..79496c94a 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/global/MuteAllCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/global/MuteAllCommandTest.java @@ -3,49 +3,39 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.CommonServer; import me.confuser.banmanager.common.commands.CommandParser; -import me.confuser.banmanager.common.commands.CommonCommand; import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.PlayerData; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class MuteAllCommandTest extends BasePluginDbTest { private MuteAllCommand cmd; - @Before + @BeforeEach public void setupCmd() { - for (CommonCommand command : plugin.getCommands()) { - if (command.getCommandName().equals("muteall")) { - this.cmd = (MuteAllCommand) command; - break; - } - } + cmd = requireCommand("muteall"); } @Test public void shouldCreateGlobalMute() throws SQLException { - Assume.assumeNotNull(cmd); PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "global mute test"}; assert (cmd.onCommand(sender, new CommandParser(plugin, args, 1))); - // Verify the command was executed await().untilAsserted(() -> verify(sender, atLeastOnce()).sendMessage(anyString())); } @Test public void shouldFailIfNoReasonGiven() { - Assume.assumeNotNull(cmd); CommonSender sender = plugin.getServer().getConsoleSender(); String[] args = new String[]{"confuser"}; @@ -54,7 +44,6 @@ public void shouldFailIfNoReasonGiven() { @Test public void shouldFailIfPlayerNotFound() { - Assume.assumeNotNull(cmd); CommonSender sender = spy(plugin.getServer().getConsoleSender()); String playerName = testUtils.createRandomPlayerName(); String[] args = new String[]{playerName, "test"}; @@ -65,9 +54,8 @@ public void shouldFailIfPlayerNotFound() { @Test public void shouldNotifyOnGlobalMute() throws SQLException { - Assume.assumeNotNull(cmd); PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName(), "global mute notification test"}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/global/UnbanAllCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/global/UnbanAllCommandTest.java index 2e23ddcf6..2c884c0bb 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/global/UnbanAllCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/global/UnbanAllCommandTest.java @@ -3,55 +3,44 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.CommonServer; import me.confuser.banmanager.common.commands.CommandParser; -import me.confuser.banmanager.common.commands.CommonCommand; import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.data.global.GlobalPlayerBanData; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class UnbanAllCommandTest extends BasePluginDbTest { private UnbanAllCommand cmd; - @Before + @BeforeEach public void setupCmd() { - for (CommonCommand command : plugin.getCommands()) { - if (command.getCommandName().equals("unbanall")) { - this.cmd = (UnbanAllCommand) command; - break; - } - } + cmd = requireCommand("unbanall"); } @Test public void shouldRemoveGlobalBan() throws SQLException { - Assume.assumeNotNull(cmd); PlayerData player = testUtils.createRandomPlayer(); PlayerData actor = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); - // First create a global ban GlobalPlayerBanData ban = new GlobalPlayerBanData(player, actor, "test"); plugin.getGlobalPlayerBanStorage().create(ban); String[] args = new String[]{player.getName()}; assert (cmd.onCommand(sender, new CommandParser(plugin, args, 0))); - // Verify the command was executed await().untilAsserted(() -> verify(sender, atLeastOnce()).sendMessage(anyString())); } @Test public void shouldFailIfPlayerNotFound() { - Assume.assumeNotNull(cmd); CommonSender sender = spy(plugin.getServer().getConsoleSender()); String playerName = testUtils.createRandomPlayerName(); String[] args = new String[]{playerName}; @@ -62,9 +51,8 @@ public void shouldFailIfPlayerNotFound() { @Test public void shouldFailIfNotGloballyBanned() { - Assume.assumeNotNull(cmd); PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName()}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/global/UnmuteAllCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/global/UnmuteAllCommandTest.java index 541ed2849..1b4fd1f12 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/global/UnmuteAllCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/global/UnmuteAllCommandTest.java @@ -3,55 +3,44 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.CommonServer; import me.confuser.banmanager.common.commands.CommandParser; -import me.confuser.banmanager.common.commands.CommonCommand; import me.confuser.banmanager.common.commands.CommonSender; import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.data.global.GlobalPlayerMuteData; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import static org.awaitility.Awaitility.await; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class UnmuteAllCommandTest extends BasePluginDbTest { private UnmuteAllCommand cmd; - @Before + @BeforeEach public void setupCmd() { - for (CommonCommand command : plugin.getCommands()) { - if (command.getCommandName().equals("unmuteall")) { - this.cmd = (UnmuteAllCommand) command; - break; - } - } + cmd = requireCommand("unmuteall"); } @Test public void shouldRemoveGlobalMute() throws SQLException { - Assume.assumeNotNull(cmd); PlayerData player = testUtils.createRandomPlayer(); PlayerData actor = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); - // First create a global mute GlobalPlayerMuteData mute = new GlobalPlayerMuteData(player, actor, "test", false); plugin.getGlobalPlayerMuteStorage().create(mute); String[] args = new String[]{player.getName()}; assert (cmd.onCommand(sender, new CommandParser(plugin, args, 0))); - // Verify the command was executed await().untilAsserted(() -> verify(sender, atLeastOnce()).sendMessage(anyString())); } @Test public void shouldFailIfPlayerNotFound() { - Assume.assumeNotNull(cmd); CommonSender sender = spy(plugin.getServer().getConsoleSender()); String playerName = testUtils.createRandomPlayerName(); String[] args = new String[]{playerName}; @@ -62,9 +51,8 @@ public void shouldFailIfPlayerNotFound() { @Test public void shouldFailIfNotGloballyMuted() { - Assume.assumeNotNull(cmd); PlayerData player = testUtils.createRandomPlayer(); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = spy(server.getConsoleSender()); String[] args = new String[]{player.getName()}; diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/report/AssignSubCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/report/AssignSubCommandTest.java index 5a1736a1b..c60d455e1 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/report/AssignSubCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/report/AssignSubCommandTest.java @@ -3,11 +3,11 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.data.PlayerReportData; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.sql.SQLException; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class AssignSubCommandTest extends BasePluginDbTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/commands/report/CloseSubCommandTest.java b/common/src/test/java/me/confuser/banmanager/common/commands/report/CloseSubCommandTest.java index b6df4bb4c..85ccddceb 100644 --- a/common/src/test/java/me/confuser/banmanager/common/commands/report/CloseSubCommandTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/commands/report/CloseSubCommandTest.java @@ -3,11 +3,11 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.data.PlayerReportData; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.sql.SQLException; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class CloseSubCommandTest extends BasePluginDbTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/configs/ConfigReloadTest.java b/common/src/test/java/me/confuser/banmanager/common/configs/ConfigReloadTest.java index 040092529..a8cc0dfab 100644 --- a/common/src/test/java/me/confuser/banmanager/common/configs/ConfigReloadTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/configs/ConfigReloadTest.java @@ -4,37 +4,35 @@ import me.confuser.banmanager.common.CommonLogger; import me.confuser.banmanager.common.TestLogger; import me.confuser.banmanager.common.util.Message; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class ConfigReloadTest extends BasePluginTest { @Test public void configLoadReturnsFalseForInvalidYaml() throws IOException { - // Create a file with invalid YAML - File invalidFile = new File(temporaryFolder.getRoot(), "invalid.yml"); + File invalidFile = new File(temporaryFolder, "invalid.yml"); try (FileWriter writer = new FileWriter(invalidFile)) { writer.write("invalid: yaml: content: [unclosed"); } CommonLogger logger = new TestLogger(); - TestConfig config = new TestConfig(temporaryFolder.getRoot(), invalidFile, logger); + TestConfig config = new TestConfig(temporaryFolder, invalidFile, logger); boolean result = config.load(); - assertFalse("Config.load() should return false for invalid YAML", result); + assertFalse(result, "Config.load() should return false for invalid YAML"); } @Test public void configLoadReturnsTrueForValidYaml() throws IOException { - // Create a file with valid YAML - File validFile = new File(temporaryFolder.getRoot(), "valid.yml"); + File validFile = new File(temporaryFolder, "valid.yml"); try (FileWriter writer = new FileWriter(validFile)) { writer.write("key: value\n"); writer.write("nested:\n"); @@ -42,66 +40,58 @@ public void configLoadReturnsTrueForValidYaml() throws IOException { } CommonLogger logger = new TestLogger(); - TestConfig config = new TestConfig(temporaryFolder.getRoot(), validFile, logger); + TestConfig config = new TestConfig(temporaryFolder, validFile, logger); boolean result = config.load(); - assertTrue("Config.load() should return true for valid YAML", result); + assertTrue(result, "Config.load() should return true for valid YAML"); assertEquals("value", config.conf.getString("key")); assertEquals("data", config.conf.getString("nested.child")); } @Test public void configLoadReturnsFalseForMissingFile() { - File missingFile = new File(temporaryFolder.getRoot(), "nonexistent.yml"); + File missingFile = new File(temporaryFolder, "nonexistent.yml"); CommonLogger logger = new TestLogger(); - TestConfig config = new TestConfig(temporaryFolder.getRoot(), missingFile, logger); + TestConfig config = new TestConfig(temporaryFolder, missingFile, logger); boolean result = config.load(); - assertFalse("Config.load() should return false for missing file", result); + assertFalse(result, "Config.load() should return false for missing file"); } @Test public void setupConfigsPreservesPreviousSettingsOnReloadFailure() throws IOException { - // First, verify the initial config loaded successfully - assertNotNull("Initial config should be loaded", plugin.getConfig()); + assertNotNull(plugin.getConfig(), "Initial config should be loaded"); DefaultConfig originalConfig = plugin.getConfig(); - // Corrupt the config.yml file with invalid YAML - File configFile = new File(temporaryFolder.getRoot(), "config.yml"); + File configFile = new File(temporaryFolder, "config.yml"); try (FileWriter writer = new FileWriter(configFile)) { writer.write("invalid: yaml: [unclosed bracket"); } - // Reload configs plugin.setupConfigs(); - // The original config should still be in place - assertSame("Config should be preserved after failed reload", originalConfig, plugin.getConfig()); + assertSame(originalConfig, plugin.getConfig(), "Config should be preserved after failed reload"); } @Test public void setupConfigsReplacesConfigOnSuccessfulReload() throws IOException { - // Get the original config DefaultConfig originalConfig = plugin.getConfig(); - assertNotNull("Initial config should be loaded", originalConfig); + assertNotNull(originalConfig, "Initial config should be loaded"); - // Reload configs (file is still valid) plugin.setupConfigs(); - // A new config object should have been created - assertNotSame("Config should be replaced after successful reload", originalConfig, plugin.getConfig()); + assertNotSame(originalConfig, plugin.getConfig(), "Config should be replaced after successful reload"); } @Test public void messagesArePreservedWhenConfigFails() throws IOException { String originalMessage = Message.getString("configReloaded"); - assertNotNull("configReloaded message should exist", originalMessage); + assertNotNull(originalMessage, "configReloaded message should exist"); - // Corrupt the messages/messages_en.yml so reload yields no usable messages - File messagesEnFile = new File(temporaryFolder.getRoot(), "messages/messages_en.yml"); + File messagesEnFile = new File(temporaryFolder, "messages/messages_en.yml"); try (FileWriter writer = new FileWriter(messagesEnFile)) { writer.write("invalid: yaml: [unclosed"); } @@ -109,28 +99,24 @@ public void messagesArePreservedWhenConfigFails() throws IOException { plugin.setupConfigs(); String afterReloadMessage = Message.getString("configReloaded"); - assertEquals("Messages should be preserved after failed reload", originalMessage, afterReloadMessage); + assertEquals(originalMessage, afterReloadMessage, "Messages should be preserved after failed reload"); } @Test public void messagesAreUpdatedOnSuccessfulReload() throws IOException { - // Get the original message String originalMessage = Message.getString("configReloaded"); - assertNotNull("configReloaded message should exist", originalMessage); + assertNotNull(originalMessage, "configReloaded message should exist"); - // Modify the messages/messages_en.yml file with a new message value - File messagesFile = new File(temporaryFolder.getRoot(), "messages/messages_en.yml"); + File messagesFile = new File(temporaryFolder, "messages/messages_en.yml"); try (FileWriter writer = new FileWriter(messagesFile)) { writer.write("messages:\n"); writer.write(" configReloaded: \"New reload message\"\n"); } - // Reload configs plugin.setupConfigs(); - // Message should be updated String afterReloadMessage = Message.getString("configReloaded"); - assertEquals("Messages should be updated after successful reload", "New reload message", afterReloadMessage); + assertEquals("New reload message", afterReloadMessage, "Messages should be updated after successful reload"); } /** @@ -150,7 +136,6 @@ public void afterLoad() { @Override public void onSave() { - // No-op for testing } public boolean wasAfterLoadCalled() { @@ -160,102 +145,91 @@ public boolean wasAfterLoadCalled() { @Test public void afterLoadIsNotCalledOnFailure() throws IOException { - // Create a file with invalid YAML - File invalidFile = new File(temporaryFolder.getRoot(), "invalid.yml"); + File invalidFile = new File(temporaryFolder, "invalid.yml"); try (FileWriter writer = new FileWriter(invalidFile)) { writer.write("invalid: yaml: [unclosed"); } CommonLogger logger = new TestLogger(); - TestConfig config = new TestConfig(temporaryFolder.getRoot(), invalidFile, logger); + TestConfig config = new TestConfig(temporaryFolder, invalidFile, logger); config.load(); - assertFalse("afterLoad() should not be called when loading fails", config.wasAfterLoadCalled()); + assertFalse(config.wasAfterLoadCalled(), "afterLoad() should not be called when loading fails"); } @Test public void afterLoadIsCalledOnSuccess() throws IOException { - // Create a file with valid YAML - File validFile = new File(temporaryFolder.getRoot(), "valid.yml"); + File validFile = new File(temporaryFolder, "valid.yml"); try (FileWriter writer = new FileWriter(validFile)) { writer.write("key: value\n"); } CommonLogger logger = new TestLogger(); - TestConfig config = new TestConfig(temporaryFolder.getRoot(), validFile, logger); + TestConfig config = new TestConfig(temporaryFolder, validFile, logger); config.load(); - assertTrue("afterLoad() should be called when loading succeeds", config.wasAfterLoadCalled()); + assertTrue(config.wasAfterLoadCalled(), "afterLoad() should be called when loading succeeds"); } @Test public void saveDoesNotOverwriteFileAfterFailedReload() throws IOException { - // Create initial valid config - File configFile = new File(temporaryFolder.getRoot(), "saveable.yml"); + File configFile = new File(temporaryFolder, "saveable.yml"); try (FileWriter writer = new FileWriter(configFile)) { writer.write("key: originalValue\n"); } CommonLogger logger = new TestLogger(); - SaveableTestConfig config = new SaveableTestConfig(temporaryFolder.getRoot(), configFile, logger); - assertTrue("Initial load should succeed", config.load()); + SaveableTestConfig config = new SaveableTestConfig(temporaryFolder, configFile, logger); + assertTrue(config.load(), "Initial load should succeed"); - // User edits the file (makes it invalid) String invalidContent = "key: editedValue\ninvalid: yaml: [unclosed"; try (FileWriter writer = new FileWriter(configFile)) { writer.write(invalidContent); } - // Reload fails - assertFalse("Reload should fail for invalid YAML", config.load()); + assertFalse(config.load(), "Reload should fail for invalid YAML"); - // Now save is called (e.g., on plugin disable) config.save(); - // The file should NOT have been overwritten with old content String fileContent = new String(Files.readAllBytes(configFile.toPath())); - assertEquals("File should not be overwritten after failed reload", invalidContent, fileContent); + assertEquals(invalidContent, fileContent, "File should not be overwritten after failed reload"); } @Test public void saveOverwritesFileAfterSuccessfulReload() throws IOException { - // Create initial valid config - File configFile = new File(temporaryFolder.getRoot(), "saveable.yml"); + File configFile = new File(temporaryFolder, "saveable.yml"); try (FileWriter writer = new FileWriter(configFile)) { writer.write("key: originalValue\n"); } CommonLogger logger = new TestLogger(); - SaveableTestConfig config = new SaveableTestConfig(temporaryFolder.getRoot(), configFile, logger); - assertTrue("Initial load should succeed", config.load()); + SaveableTestConfig config = new SaveableTestConfig(temporaryFolder, configFile, logger); + assertTrue(config.load(), "Initial load should succeed"); - // Modify the in-memory config config.conf.set("key", "modifiedValue"); - // Save should work config.save(); - // Verify file was updated String fileContent = new String(Files.readAllBytes(configFile.toPath())); - assertTrue("File should contain modified value", fileContent.contains("modifiedValue")); + assertTrue(fileContent.contains("modifiedValue"), "File should contain modified value"); } @Test public void saveInAfterLoadPersistsChanges() throws IOException { - File configFile = new File(temporaryFolder.getRoot(), "self-save.yml"); + File configFile = new File(temporaryFolder, "self-save.yml"); try (FileWriter writer = new FileWriter(configFile)) { writer.write("key: originalValue\n"); } CommonLogger logger = new TestLogger(); - SelfSavingTestConfig config = new SelfSavingTestConfig(temporaryFolder.getRoot(), configFile, logger); + SelfSavingTestConfig config = new SelfSavingTestConfig(temporaryFolder, configFile, logger); - assertTrue("Load should succeed for valid YAML", config.load()); + assertTrue(config.load(), "Load should succeed for valid YAML"); String fileContent = new String(Files.readAllBytes(configFile.toPath())); - assertTrue("afterLoad() save should persist updated value", fileContent.contains("updatedInAfterLoad")); + assertTrue(fileContent.contains("updatedInAfterLoad"), "afterLoad() save should persist updated value"); } /** @@ -268,12 +242,10 @@ public SaveableTestConfig(File dataFolder, File file, CommonLogger logger) { @Override public void afterLoad() { - // No-op } @Override public void onSave() { - // No-op } } @@ -293,7 +265,6 @@ public void afterLoad() { @Override public void onSave() { - // No-op } } } diff --git a/common/src/test/java/me/confuser/banmanager/common/configs/ConsoleConfigTest.java b/common/src/test/java/me/confuser/banmanager/common/configs/ConsoleConfigTest.java index d3cf46cd1..3d06d6978 100644 --- a/common/src/test/java/me/confuser/banmanager/common/configs/ConsoleConfigTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/configs/ConsoleConfigTest.java @@ -1,10 +1,10 @@ package me.confuser.banmanager.common.configs; import me.confuser.banmanager.common.BasePluginTest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ConsoleConfigTest extends BasePluginTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/configs/DefaultConfigTest.java b/common/src/test/java/me/confuser/banmanager/common/configs/DefaultConfigTest.java index 9e49f63c2..e8290b110 100644 --- a/common/src/test/java/me/confuser/banmanager/common/configs/DefaultConfigTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/configs/DefaultConfigTest.java @@ -1,9 +1,9 @@ package me.confuser.banmanager.common.configs; import me.confuser.banmanager.common.BasePluginDbTest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class DefaultConfigTest extends BasePluginDbTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/configs/GeoIpConfigTest.java b/common/src/test/java/me/confuser/banmanager/common/configs/GeoIpConfigTest.java index 14284a177..d6c959c50 100644 --- a/common/src/test/java/me/confuser/banmanager/common/configs/GeoIpConfigTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/configs/GeoIpConfigTest.java @@ -1,9 +1,9 @@ package me.confuser.banmanager.common.configs; import me.confuser.banmanager.common.BasePluginTest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertFalse; +import static org.junit.jupiter.api.Assertions.assertFalse; public class GeoIpConfigTest extends BasePluginTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/configs/NotificationsConfigTest.java b/common/src/test/java/me/confuser/banmanager/common/configs/NotificationsConfigTest.java index 171eac588..54fa15b02 100644 --- a/common/src/test/java/me/confuser/banmanager/common/configs/NotificationsConfigTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/configs/NotificationsConfigTest.java @@ -1,9 +1,9 @@ package me.confuser.banmanager.common.configs; import me.confuser.banmanager.common.BasePluginTest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class NotificationsConfigTest extends BasePluginTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/configs/SchedulesConfigTest.java b/common/src/test/java/me/confuser/banmanager/common/configs/SchedulesConfigTest.java index 8f4bcd73a..c9ee8dd8b 100644 --- a/common/src/test/java/me/confuser/banmanager/common/configs/SchedulesConfigTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/configs/SchedulesConfigTest.java @@ -1,9 +1,9 @@ package me.confuser.banmanager.common.configs; import me.confuser.banmanager.common.BasePluginTest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class SchedulesConfigTest extends BasePluginTest { @Test diff --git a/common/src/test/java/me/confuser/banmanager/common/listeners/CommonJoinListenerTest.java b/common/src/test/java/me/confuser/banmanager/common/listeners/CommonJoinListenerTest.java index cd6f9d8c6..a334aefc8 100644 --- a/common/src/test/java/me/confuser/banmanager/common/listeners/CommonJoinListenerTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/listeners/CommonJoinListenerTest.java @@ -6,8 +6,8 @@ import me.confuser.banmanager.common.ipaddr.IPAddress; import me.confuser.banmanager.common.util.IPUtils; import me.confuser.banmanager.common.util.Message; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.net.InetAddress; import java.net.UnknownHostException; @@ -15,7 +15,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class CommonJoinListenerTest extends BasePluginDbTest { @@ -23,7 +23,7 @@ public class CommonJoinListenerTest extends BasePluginDbTest { private CommonJoinListener listener; private IPAddress testIp; - @Before + @BeforeEach public void setupListener() throws UnknownHostException { listener = new CommonJoinListener(plugin); testIp = IPUtils.toIPAddress(InetAddress.getByName("192.168.1.100")); @@ -59,7 +59,7 @@ public void banCheckShouldPopulateMultiaccountsCache() throws Exception { // The cache should have been populated - we can't directly access it, // but we can verify by calling onPlayerLogin and seeing if it uses the cached value // For now, verify that the method completed without error - assertFalse("Should not deny during banCheck for multiaccounts", denied.get()); + assertFalse(denied.get(), "Should not deny during banCheck for multiaccounts"); } @Test @@ -97,7 +97,7 @@ public void onPlayerLoginShouldDenyWhenCachedCountExceedsLimit() throws Exceptio testListener.onPlayerLogin(testPlayer, loginHandler); - assertTrue("Should deny login when multiaccounts count exceeds limit", loginDenied.get()); + assertTrue(loginDenied.get(), "Should deny login when multiaccounts count exceeds limit"); } @Test @@ -131,7 +131,7 @@ public void onPlayerLoginShouldAllowWhenPlayerHasExemptPermission() throws Excep AtomicBoolean loginDenied = new AtomicBoolean(false); testListener.onPlayerLogin(testPlayer, createHandler(loginDenied)); - assertFalse("Should allow login when player has exempt permission", loginDenied.get()); + assertFalse(loginDenied.get(), "Should allow login when player has exempt permission"); } @Test @@ -158,7 +158,7 @@ public void onPlayerLoginShouldAllowWhenCacheIsEmpty() throws Exception { AtomicBoolean loginDenied = new AtomicBoolean(false); testListener.onPlayerLogin(testPlayer, createHandler(loginDenied)); - assertFalse("Should allow login (fail-open) when cache is empty", loginDenied.get()); + assertFalse(loginDenied.get(), "Should allow login (fail-open) when cache is empty"); } @Test @@ -191,7 +191,7 @@ public void onPlayerLoginShouldAllowWhenCountIsWithinLimit() throws Exception { AtomicBoolean loginDenied = new AtomicBoolean(false); testListener.onPlayerLogin(testPlayer, createHandler(loginDenied)); - assertFalse("Should allow login when count is within limit", loginDenied.get()); + assertFalse(loginDenied.get(), "Should allow login when count is within limit"); } @Test @@ -206,13 +206,13 @@ public void shouldRecordSessionOnJoin() throws Exception { testListener.onPreJoin(existingPlayer.getUUID(), existingPlayer.getName(), testIp); // Session should be in DB and tracked in memory - assertTrue("Session should be active", plugin.getPlayerHistoryStorage().hasActiveSession(existingPlayer.getUUID())); + assertTrue(plugin.getPlayerHistoryStorage().hasActiveSession(existingPlayer.getUUID()), "Session should be active"); // Verify the session is in the database with correct data java.util.List sessions = plugin.getPlayerHistoryStorage().queryForAll(); - assertEquals("Should have one session", 1, sessions.size()); - assertEquals("Recorded name should match", existingPlayer.getName(), sessions.get(0).getName()); - assertNotNull("Session should have IP", sessions.get(0).getIp()); + assertEquals(1, sessions.size(), "Should have one session"); + assertEquals(existingPlayer.getName(), sessions.get(0).getName(), "Recorded name should match"); + assertNotNull(sessions.get(0).getIp(), "Session should have IP"); // Clean up - end the session plugin.getPlayerHistoryStorage().endSession(existingPlayer.getUUID()); @@ -236,13 +236,13 @@ public void shouldRecordSessionWithoutIpWhenLogIpsDisabled() throws Exception { testListener.onPreJoin(existingPlayer.getUUID(), existingPlayer.getName(), testIp); // Session should be active - assertTrue("Session should be active", plugin.getPlayerHistoryStorage().hasActiveSession(existingPlayer.getUUID())); + assertTrue(plugin.getPlayerHistoryStorage().hasActiveSession(existingPlayer.getUUID()), "Session should be active"); // Verify session has null IP in database java.util.List sessions = plugin.getPlayerHistoryStorage().queryForAll(); - assertEquals("Should have one session", 1, sessions.size()); - assertEquals("Recorded name should match", existingPlayer.getName(), sessions.get(0).getName()); - assertNull("Session should NOT have IP when logIps is disabled", sessions.get(0).getIp()); + assertEquals(1, sessions.size(), "Should have one session"); + assertEquals(existingPlayer.getName(), sessions.get(0).getName(), "Recorded name should match"); + assertNull(sessions.get(0).getIp(), "Session should NOT have IP when logIps is disabled"); // Clean up - end the session plugin.getPlayerHistoryStorage().endSession(existingPlayer.getUUID()); diff --git a/common/src/test/java/me/confuser/banmanager/common/listeners/NoteListenerTest.java b/common/src/test/java/me/confuser/banmanager/common/listeners/NoteListenerTest.java index 7f03dee52..bc9c6e8d9 100755 --- a/common/src/test/java/me/confuser/banmanager/common/listeners/NoteListenerTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/listeners/NoteListenerTest.java @@ -5,10 +5,10 @@ import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.data.PlayerNoteData; import me.confuser.banmanager.common.util.Message; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; public class NoteListenerTest extends BasePluginDbTest { @@ -16,7 +16,7 @@ public class NoteListenerTest extends BasePluginDbTest { public void shouldBroadcast() { PlayerData player = testUtils.createRandomPlayer(); BanManagerPlugin plugin = spy(this.plugin); - CommonServer server = spy(plugin.getServer()); + CommonServer server = this.server; CommonSender sender = plugin.getServer().getConsoleSender(); PlayerNoteData data = new PlayerNoteData(player, sender.getData(), "test"); CommonPlayer testPlayer = spy(new TestPlayer(sender.getData().getUUID(), sender.getName(), false)); diff --git a/common/src/test/java/me/confuser/banmanager/common/runnables/BmRunnableTest.java b/common/src/test/java/me/confuser/banmanager/common/runnables/BmRunnableTest.java index 4fa6e28d5..8a30e2510 100644 --- a/common/src/test/java/me/confuser/banmanager/common/runnables/BmRunnableTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/runnables/BmRunnableTest.java @@ -1,9 +1,9 @@ package me.confuser.banmanager.common.runnables; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Tests for BmRunnable schedule disable semantics. @@ -20,7 +20,7 @@ public void scheduleZeroDisablesExecution() { // Test the logic that schedule <= 0 means disabled int scheduleValue = 0; boolean shouldExecute = scheduleValue > 0; - assertFalse("Schedule 0 should disable execution", shouldExecute); + assertFalse(shouldExecute, "Schedule 0 should disable execution"); } /** @@ -30,7 +30,7 @@ public void scheduleZeroDisablesExecution() { public void scheduleNegativeDisablesExecution() { int scheduleValue = -1; boolean shouldExecute = scheduleValue > 0; - assertFalse("Negative schedule should disable execution", shouldExecute); + assertFalse(shouldExecute, "Negative schedule should disable execution"); } /** @@ -40,6 +40,6 @@ public void scheduleNegativeDisablesExecution() { public void schedulePositiveAllowsExecution() { int scheduleValue = 5; boolean scheduleAllowsExecution = scheduleValue > 0; - assertTrue("Positive schedule should allow execution (if other conditions met)", scheduleAllowsExecution); + assertTrue(scheduleAllowsExecution, "Positive schedule should allow execution (if other conditions met)"); } } diff --git a/common/src/test/java/me/confuser/banmanager/common/runnables/RollbackSyncTest.java b/common/src/test/java/me/confuser/banmanager/common/runnables/RollbackSyncTest.java index db93b1279..451191f3f 100644 --- a/common/src/test/java/me/confuser/banmanager/common/runnables/RollbackSyncTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/runnables/RollbackSyncTest.java @@ -5,17 +5,17 @@ import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.data.PlayerMuteData; import me.confuser.banmanager.common.data.RollbackData; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class RollbackSyncTest extends BasePluginDbTest { private RollbackSync rollbackSync; - @Before + @BeforeEach public void setupSync() { rollbackSync = new RollbackSync(plugin); } diff --git a/common/src/test/java/me/confuser/banmanager/common/storage/IpBanStorageTest.java b/common/src/test/java/me/confuser/banmanager/common/storage/IpBanStorageTest.java index 4634a2859..351474dfe 100644 --- a/common/src/test/java/me/confuser/banmanager/common/storage/IpBanStorageTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/storage/IpBanStorageTest.java @@ -5,11 +5,11 @@ import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.ipaddr.IPAddress; import me.confuser.banmanager.common.util.IPUtils; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.sql.SQLException; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class IpBanStorageTest extends BasePluginDbTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/storage/IpRangeBanStorageTest.java b/common/src/test/java/me/confuser/banmanager/common/storage/IpRangeBanStorageTest.java index 3fc2c0679..f53bb1bab 100644 --- a/common/src/test/java/me/confuser/banmanager/common/storage/IpRangeBanStorageTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/storage/IpRangeBanStorageTest.java @@ -5,11 +5,11 @@ import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.ipaddr.IPAddress; import me.confuser.banmanager.common.util.IPUtils; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.sql.SQLException; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class IpRangeBanStorageTest extends BasePluginDbTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/storage/PlayerBanStorageTest.java b/common/src/test/java/me/confuser/banmanager/common/storage/PlayerBanStorageTest.java index 9766455f0..75f81a31b 100644 --- a/common/src/test/java/me/confuser/banmanager/common/storage/PlayerBanStorageTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/storage/PlayerBanStorageTest.java @@ -3,12 +3,12 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.data.PlayerBanData; import me.confuser.banmanager.common.data.PlayerData; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import java.util.UUID; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class PlayerBanStorageTest extends BasePluginDbTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/storage/PlayerHistoryStorageTest.java b/common/src/test/java/me/confuser/banmanager/common/storage/PlayerHistoryStorageTest.java index 2878c3f5a..52eb1eb6a 100644 --- a/common/src/test/java/me/confuser/banmanager/common/storage/PlayerHistoryStorageTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/storage/PlayerHistoryStorageTest.java @@ -6,16 +6,16 @@ import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.data.PlayerHistoryData; import me.confuser.banmanager.common.data.PlayerNameSummary; -import org.junit.After; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class PlayerHistoryStorageTest extends BasePluginDbTest { - @After + @AfterEach public void clear() throws SQLException { plugin.getPlayerHistoryStorage().updateRaw("TRUNCATE TABLE " + plugin.getPlayerHistoryStorage().getTableName()); } @@ -89,7 +89,7 @@ public void shouldCreateSessionWithNullIp() throws SQLException { // Fetch from DB to verify List sessions = storage.queryForAll(); assertEquals(1, sessions.size()); - assertNull("IP should be null when logIp=false", sessions.get(0).getIp()); + assertNull(sessions.get(0).getIp(), "IP should be null when logIp=false"); assertEquals(player.getName(), sessions.get(0).getName()); } @@ -102,7 +102,7 @@ public void shouldGetNamesSummary() throws SQLException { List summary = storage.getNamesSummary(player); assertEquals(1, summary.size()); - assertEquals(player.getName(), summary.get(0).getName()); + assertEquals(player.getName(), summary.get(0).name()); } @Test @@ -162,8 +162,8 @@ public void shouldSetDatabaseTimestampsOnSession() throws SQLException { assertEquals(1, sessions.size()); PlayerHistoryData session = sessions.get(0); - assertTrue("Join time should be set", session.getJoin() > 0); - assertTrue("Leave time should be set", session.getLeave() > 0); - assertTrue("Leave should be >= Join", session.getLeave() >= session.getJoin()); + assertTrue(session.getJoin() > 0, "Join time should be set"); + assertTrue(session.getLeave() > 0, "Leave time should be set"); + assertTrue(session.getLeave() >= session.getJoin(), "Leave should be >= Join"); } } diff --git a/common/src/test/java/me/confuser/banmanager/common/storage/PlayerMuteStorageTest.java b/common/src/test/java/me/confuser/banmanager/common/storage/PlayerMuteStorageTest.java index f44efa61c..92e7d3bd4 100644 --- a/common/src/test/java/me/confuser/banmanager/common/storage/PlayerMuteStorageTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/storage/PlayerMuteStorageTest.java @@ -5,12 +5,11 @@ import me.confuser.banmanager.common.data.PlayerMuteData; import me.confuser.banmanager.common.data.PlayerMuteRecord; import me.confuser.banmanager.common.ormlite.dao.CloseableIterator; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import java.io.IOException; import java.sql.SQLException; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class PlayerMuteStorageTest extends BasePluginDbTest { @@ -233,7 +232,7 @@ public void shouldNotConsiderPausedMuteExpired() throws SQLException { } @Test - public void shouldNotRestoreOnlineOnlyWhenNoRemainingTime() throws SQLException, IOException { + public void shouldNotRestoreOnlineOnlyWhenNoRemainingTime() throws Exception { PlayerData player = testUtils.createRandomPlayer(); PlayerData actor = testUtils.createRandomPlayer(); PlayerData unmuter = testUtils.createRandomPlayer(); @@ -268,7 +267,7 @@ public void shouldNotRestoreOnlineOnlyWhenNoRemainingTime() throws SQLException, } @Test - public void shouldRestoreOnlineOnlyWithRemainingTime() throws SQLException, IOException { + public void shouldRestoreOnlineOnlyWithRemainingTime() throws Exception { PlayerData player = testUtils.createRandomPlayer(); PlayerData actor = testUtils.createRandomPlayer(); PlayerData unmuter = testUtils.createRandomPlayer(); diff --git a/common/src/test/java/me/confuser/banmanager/common/storage/PlayerStorageTest.java b/common/src/test/java/me/confuser/banmanager/common/storage/PlayerStorageTest.java index 350fc450f..eb7ee4503 100644 --- a/common/src/test/java/me/confuser/banmanager/common/storage/PlayerStorageTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/storage/PlayerStorageTest.java @@ -3,12 +3,12 @@ import me.confuser.banmanager.common.BasePluginDbTest; import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.ormlite.dao.Dao; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.sql.SQLException; import java.util.UUID; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class PlayerStorageTest extends BasePluginDbTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/storage/PlayerWarnStorageTest.java b/common/src/test/java/me/confuser/banmanager/common/storage/PlayerWarnStorageTest.java index 6bf031b19..c7e994656 100644 --- a/common/src/test/java/me/confuser/banmanager/common/storage/PlayerWarnStorageTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/storage/PlayerWarnStorageTest.java @@ -4,11 +4,11 @@ import me.confuser.banmanager.common.data.PlayerData; import me.confuser.banmanager.common.data.PlayerWarnData; import me.confuser.banmanager.common.ormlite.dao.CloseableIterator; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.sql.SQLException; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class PlayerWarnStorageTest extends BasePluginDbTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/storage/conversion/LiteBansImportTest.java b/common/src/test/java/me/confuser/banmanager/common/storage/conversion/LiteBansImportTest.java index de767113b..42dbbb6bd 100644 --- a/common/src/test/java/me/confuser/banmanager/common/storage/conversion/LiteBansImportTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/storage/conversion/LiteBansImportTest.java @@ -6,14 +6,13 @@ import me.confuser.banmanager.common.ipaddr.IPAddressString; import me.confuser.banmanager.common.ormlite.dao.CloseableIterator; import me.confuser.banmanager.common.ormlite.support.DatabaseConnection; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import java.io.IOException; import java.sql.SQLException; import java.util.UUID; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; /** * Tests for the LiteBans to BanManager import functionality. @@ -30,8 +29,8 @@ public class LiteBansImportTest extends BasePluginDbTest { private static final String PLAYER_UUID_3 = "550e8400-e29b-41d4-a716-446655440003"; private static final String ACTOR_UUID = "550e8400-e29b-41d4-a716-446655440099"; - @Before - public void setupLiteBansTables() throws SQLException, IOException { + @BeforeEach + public void setupLiteBansTables() throws Exception { createLiteBansSchema(); insertTestData(); } @@ -39,7 +38,7 @@ public void setupLiteBansTables() throws SQLException, IOException { /** * Creates the LiteBans table schema in the test database. */ - private void createLiteBansSchema() throws SQLException, IOException { + private void createLiteBansSchema() throws Exception { try (DatabaseConnection conn = plugin.getLocalConn().getReadWriteConnection("")) { // Create bans table conn.executeStatement( @@ -146,7 +145,7 @@ private void createLiteBansSchema() throws SQLException, IOException { /** * Inserts test data into the LiteBans tables. */ - private void insertTestData() throws SQLException, IOException { + private void insertTestData() throws Exception { long currentTime = System.currentTimeMillis(); long pastTime = currentTime - 86400000L; // 1 day ago @@ -254,12 +253,12 @@ public void shouldImportActivePlayerBan() throws SQLException { runImport(); UUID playerUuid = UUID.fromString(PLAYER_UUID_1); - assertTrue("Player should be banned", plugin.getPlayerBanStorage().isBanned(playerUuid)); + assertTrue(plugin.getPlayerBanStorage().isBanned(playerUuid), "Player should be banned"); PlayerBanData ban = plugin.getPlayerBanStorage().getBan(playerUuid); - assertNotNull("Ban data should exist", ban); + assertNotNull(ban, "Ban data should exist"); assertEquals("Test ban reason", ban.getReason()); - assertFalse("Ban should not be silent", ban.isSilent()); + assertFalse(ban.isSilent(), "Ban should not be silent"); } @Test @@ -269,7 +268,7 @@ public void shouldImportActiveIpBan() { // Check that IP ban was imported // The IP 10.0.0.1 should be banned IPAddress ip = new IPAddressString("10.0.0.1").getAddress(); - assertTrue("IP should be banned", plugin.getIpBanStorage().isBanned(ip)); + assertTrue(plugin.getIpBanStorage().isBanned(ip), "IP should be banned"); } @Test @@ -278,7 +277,7 @@ public void shouldImportActiveIpRangeBan() { // Check that an IP within the range 172.16.0.0/16 is banned IPAddress ip = new IPAddressString("172.16.1.1").getAddress(); - assertTrue("IP in range should be banned", plugin.getIpRangeBanStorage().isBanned(ip)); + assertTrue(plugin.getIpRangeBanStorage().isBanned(ip), "IP in range should be banned"); } @Test @@ -286,10 +285,10 @@ public void shouldImportActivePlayerMute() throws SQLException { runImport(); UUID playerUuid = UUID.fromString(PLAYER_UUID_1); - assertTrue("Player should be muted", plugin.getPlayerMuteStorage().isMuted(playerUuid)); + assertTrue(plugin.getPlayerMuteStorage().isMuted(playerUuid), "Player should be muted"); PlayerMuteData mute = plugin.getPlayerMuteStorage().getMute(playerUuid); - assertNotNull("Mute data should exist", mute); + assertNotNull(mute, "Mute data should exist"); assertEquals("Test mute reason", mute.getReason()); } @@ -298,11 +297,11 @@ public void shouldImportActiveIpMute() { runImport(); IPAddress ip = new IPAddressString("10.0.0.2").getAddress(); - assertTrue("IP should be muted", plugin.getIpMuteStorage().isMuted(ip)); + assertTrue(plugin.getIpMuteStorage().isMuted(ip), "IP should be muted"); } @Test - public void shouldImportWarningWithCorrectReadStatus() throws SQLException, IOException { + public void shouldImportWarningWithCorrectReadStatus() throws Exception { runImport(); // Check warnings for PLAYER_UUID_1 - should have warned=true (read=true) @@ -314,11 +313,11 @@ public void shouldImportWarningWithCorrectReadStatus() throws SQLException, IOEx while (warnings.hasNext()) { PlayerWarnData warn = warnings.next(); if (warn.getReason().equals("Test warning")) { - assertTrue("Warning should be marked as read", warn.isRead()); + assertTrue(warn.isRead(), "Warning should be marked as read"); foundReadWarning = true; } } - assertTrue("Should have found the read warning", foundReadWarning); + assertTrue(foundReadWarning, "Should have found the read warning"); } } @@ -331,7 +330,7 @@ public void shouldImportKick() throws SQLException { // Verify at least one kick was imported for this player long kickCount = plugin.getPlayerKickStorage().getCount(player); - assertTrue("Should have at least one kick", kickCount > 0); + assertTrue(kickCount > 0, "Should have at least one kick"); } @Test @@ -340,8 +339,7 @@ public void shouldSkipInvalidUuids() { runImport(); // Verify import completed successfully by checking valid entries exist - assertTrue("Valid player ban should exist", - plugin.getPlayerBanStorage().isBanned(UUID.fromString(PLAYER_UUID_1))); + assertTrue(plugin.getPlayerBanStorage().isBanned(UUID.fromString(PLAYER_UUID_1)), "Valid player ban should exist"); } @Test @@ -350,13 +348,11 @@ public void shouldHandleConsoleAsActor() { // The IP ban was created by CONSOLE, verify it imported correctly IPAddress ip = new IPAddressString("10.0.0.1").getAddress(); - assertTrue("IP ban by console should exist", plugin.getIpBanStorage().isBanned(ip)); + assertTrue(plugin.getIpBanStorage().isBanned(ip), "IP ban by console should exist"); IpBanData ban = plugin.getIpBanStorage().getBan(ip); - assertNotNull("Ban should exist", ban); - assertEquals("Actor should be console", - plugin.getPlayerStorage().getConsole().getUUID(), - ban.getActor().getUUID()); + assertNotNull(ban, "Ban should exist"); + assertEquals(plugin.getPlayerStorage().getConsole().getUUID(), ban.getActor().getUUID(), "Actor should be console"); } @Test @@ -367,13 +363,12 @@ public void shouldCreateBanRecordForRemovedBan() throws SQLException { UUID removedPlayerUuid = UUID.fromString("550e8400-e29b-41d4-a716-446655440004"); // Player should NOT be actively banned (it was removed) - assertFalse("Player should not be actively banned", - plugin.getPlayerBanStorage().isBanned(removedPlayerUuid)); + assertFalse(plugin.getPlayerBanStorage().isBanned(removedPlayerUuid), "Player should not be actively banned"); // But there should be a ban record PlayerData player = plugin.getPlayerStorage().createIfNotExists(removedPlayerUuid, "Unknown"); long recordCount = plugin.getPlayerBanRecordStorage().getCount(player); - assertTrue("Should have a ban record", recordCount > 0); + assertTrue(recordCount > 0, "Should have a ban record"); } /** diff --git a/common/src/test/java/me/confuser/banmanager/common/storage/migration/MigrationIntegrationTest.java b/common/src/test/java/me/confuser/banmanager/common/storage/migration/MigrationIntegrationTest.java index 466deb1b5..40836800d 100644 --- a/common/src/test/java/me/confuser/banmanager/common/storage/migration/MigrationIntegrationTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/storage/migration/MigrationIntegrationTest.java @@ -4,33 +4,33 @@ import me.confuser.banmanager.common.configs.PluginInfo; import me.confuser.banmanager.common.ormlite.dao.Dao; import me.confuser.banmanager.common.ormlite.dao.DaoManager; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import java.io.File; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.spy; public class MigrationIntegrationTest { - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @TempDir + public File temporaryFolder; private BanManagerPlugin plugin; private TestServer server = spy(new TestServer()); - @Before + @BeforeEach public void setup() throws Exception { CommonLogger logger = new TestLogger(); PluginInfo pluginInfo = BasePluginTest.setupConfigs(temporaryFolder); - plugin = new BanManagerPlugin(pluginInfo, logger, temporaryFolder.getRoot(), new TestScheduler(), server, new TestMetrics()); + plugin = new BanManagerPlugin(pluginInfo, logger, temporaryFolder, new TestScheduler(), server, new TestMetrics()); server.enable(plugin); } - @After + @AfterEach public void cleanup() { if (plugin != null) { plugin.disable(); @@ -44,18 +44,18 @@ public void freshInstall_marksLatestVersion() throws Exception { Dao dao = DaoManager.createDao(plugin.getLocalConn(), SchemaVersion.class); List versions = dao.queryForAll(); - assertFalse("Schema versions should have been recorded", versions.isEmpty()); + assertFalse(versions.isEmpty(), "Schema versions should have been recorded"); boolean hasLocal = false; for (SchemaVersion sv : versions) { if ("local".equals(sv.getScope())) { hasLocal = true; - assertEquals("Fresh install should mark at latest version", 2, sv.getVersion()); - assertTrue("Description should indicate fresh install", sv.getDescription().contains("fresh install")); + assertEquals(2, sv.getVersion(), "Fresh install should mark at latest version"); + assertTrue(sv.getDescription().contains("fresh install"), "Description should indicate fresh install"); } } - assertTrue("Should have a local scope version", hasLocal); + assertTrue(hasLocal, "Should have a local scope version"); } @Test @@ -65,7 +65,7 @@ public void secondEnable_isIdempotent() throws Exception { CommonLogger logger = new TestLogger(); PluginInfo pluginInfo = BasePluginTest.setupConfigs(temporaryFolder); - plugin = new BanManagerPlugin(pluginInfo, logger, temporaryFolder.getRoot(), new TestScheduler(), server, new TestMetrics()); + plugin = new BanManagerPlugin(pluginInfo, logger, temporaryFolder, new TestScheduler(), server, new TestMetrics()); server.enable(plugin); plugin.enable(); @@ -76,6 +76,6 @@ public void secondEnable_isIdempotent() throws Exception { ).getFirstResult(); int count = Integer.parseInt(rawResults[0]); - assertEquals("Should have exactly one local version row (no duplicates from second enable)", 1, count); + assertEquals(1, count, "Should have exactly one local version row (no duplicates from second enable)"); } } diff --git a/common/src/test/java/me/confuser/banmanager/common/storage/migration/MigrationRunnerTest.java b/common/src/test/java/me/confuser/banmanager/common/storage/migration/MigrationRunnerTest.java index 98e703726..6f94714a7 100644 --- a/common/src/test/java/me/confuser/banmanager/common/storage/migration/MigrationRunnerTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/storage/migration/MigrationRunnerTest.java @@ -1,10 +1,10 @@ package me.confuser.banmanager.common.storage.migration; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class MigrationRunnerTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/util/ColorUtilsTest.java b/common/src/test/java/me/confuser/banmanager/common/util/ColorUtilsTest.java index 75b44a2ac..3597103da 100644 --- a/common/src/test/java/me/confuser/banmanager/common/util/ColorUtilsTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/ColorUtilsTest.java @@ -1,7 +1,7 @@ package me.confuser.banmanager.common.util; -import org.junit.Test; -import static org.junit.Assert.*; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; public class ColorUtilsTest { @@ -9,65 +9,65 @@ public class ColorUtilsTest { public void testHexColorParsing() { String input = "&#ff0000Red Text"; String legacy = ColorUtils.toDownsampledLegacy(input); - assertFalse("Output should not contain #", legacy.contains("#")); - assertTrue("Output should contain 'Red Text'", legacy.contains("Red Text")); + assertFalse(legacy.contains("#"), "Output should not contain #"); + assertTrue(legacy.contains("Red Text"), "Output should contain 'Red Text'"); } @Test public void testMixedColors() { String input = "&cRed �ff00Green &9Blue"; String legacy = ColorUtils.toDownsampledLegacy(input); - assertFalse("Output should not contain #", legacy.contains("#")); - assertTrue("Output should contain text", legacy.contains("Red")); - assertTrue("Output should contain text", legacy.contains("Green")); - assertTrue("Output should contain text", legacy.contains("Blue")); + assertFalse(legacy.contains("#"), "Output should not contain #"); + assertTrue(legacy.contains("Red"), "Output should contain text"); + assertTrue(legacy.contains("Green"), "Output should contain text"); + assertTrue(legacy.contains("Blue"), "Output should contain text"); } @Test public void testSpigotHexFormat() { String input = "&x&f&f&0&0&0&0Red"; String legacy = ColorUtils.toDownsampledLegacy(input); - assertFalse("Output should not contain &x", legacy.contains("&x")); - assertFalse("Output should not contain #", legacy.contains("#")); - assertTrue("Output should contain 'Red'", legacy.contains("Red")); + assertFalse(legacy.contains("&x"), "Output should not contain &x"); + assertFalse(legacy.contains("#"), "Output should not contain #"); + assertTrue(legacy.contains("Red"), "Output should contain 'Red'"); } @Test public void testDownsampledJsonNoHex() { String input = "&#ff5733Orange"; String json = ColorUtils.toDownsampledJson(input); - assertFalse("JSON should not contain hex code", json.contains("#ff5733")); - assertFalse("JSON should not contain hex code", json.contains("ff5733")); - assertTrue("JSON should contain text", json.contains("Orange")); + assertFalse(json.contains("#ff5733"), "JSON should not contain hex code"); + assertFalse(json.contains("ff5733"), "JSON should not contain hex code"); + assertTrue(json.contains("Orange"), "JSON should contain text"); } @Test public void testFullJsonHasHex() { String input = "&#ff5733Orange"; String json = ColorUtils.toJson(input); - assertTrue("JSON should contain text", json.contains("Orange")); + assertTrue(json.contains("Orange"), "JSON should contain text"); } @Test public void testNewlinePreservation() { String input = "Line1\\nLine2"; String legacy = ColorUtils.toDownsampledLegacy(input); - assertTrue("Should convert \\n to newline", legacy.contains("\n")); + assertTrue(legacy.contains("\n"), "Should convert \\n to newline"); } @Test public void testPlainTextUnchanged() { String input = "Hello World"; String legacy = ColorUtils.toDownsampledLegacy(input); - assertEquals("Plain text should be unchanged", "Hello World", legacy); + assertEquals("Hello World", legacy, "Plain text should be unchanged"); } @Test public void testLegacyColorsPreserved() { String input = "&cRed &aGreen"; String legacy = ColorUtils.toDownsampledLegacy(input); - assertTrue("Should contain & codes", legacy.contains("&")); - assertTrue("Should contain text", legacy.contains("Red")); - assertTrue("Should contain text", legacy.contains("Green")); + assertTrue(legacy.contains("&"), "Should contain & codes"); + assertTrue(legacy.contains("Red"), "Should contain text"); + assertTrue(legacy.contains("Green"), "Should contain text"); } } diff --git a/common/src/test/java/me/confuser/banmanager/common/util/DateUtilsTest.java b/common/src/test/java/me/confuser/banmanager/common/util/DateUtilsTest.java index 3ef5b2cd6..3072f75a0 100755 --- a/common/src/test/java/me/confuser/banmanager/common/util/DateUtilsTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/DateUtilsTest.java @@ -1,10 +1,10 @@ package me.confuser.banmanager.common.util; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.time.ZoneOffset; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class DateUtilsTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/util/IPUtilsTest.java b/common/src/test/java/me/confuser/banmanager/common/util/IPUtilsTest.java index 1dce4991f..abfb3c5a2 100644 --- a/common/src/test/java/me/confuser/banmanager/common/util/IPUtilsTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/IPUtilsTest.java @@ -1,15 +1,15 @@ package me.confuser.banmanager.common.util; -import com.github.javafaker.Faker; +import net.datafaker.Faker; import me.confuser.banmanager.common.ipaddr.AddressStringException; import me.confuser.banmanager.common.ipaddr.IPAddress; import me.confuser.banmanager.common.ipaddr.IPAddressString; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.net.InetAddress; import java.net.UnknownHostException; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class IPUtilsTest { private Faker faker = new Faker(); @@ -105,16 +105,35 @@ public void bytesToIPAddress() { assertEquals(randomIpv4, reconstructed.toString()); } + // Curated, well-formed IPv6 addresses. We can't trust faker.internet().ipV6Address() + // alone because the previous test contained a "replaceAll(\"0\", \"\")" workaround that + // occasionally produced strings like ":::abc" which fail to parse - leaving the suite + // intermittently red without saying anything new about IPUtils. + private static final String[] SAMPLE_IPV6 = { + "2001:db8::1", + "fe80::1ff:fe23:4567:890a", + "::ffff:192.0.2.128", + "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "::", + "2607:f8b0:4005:805::200e" + }; + + private static String randomSampleIpv6() { + return SAMPLE_IPV6[(int) (Math.random() * SAMPLE_IPV6.length)]; + } + @Test public void stringToIPAddress() { assertEquals("127.0.0.1", IPUtils.toIPAddress("127.0.0.1").toString()); assertEquals("::1", IPUtils.toIPAddress("::1").toString()); String ipv4 = faker.internet().ipV4Address(); - String ipv6 = faker.internet().ipV6Address().replaceAll("0", ""); - assertEquals(ipv4, IPUtils.toIPAddress(ipv4).toString()); - assertEquals(ipv6, IPUtils.toIPAddress(ipv6).toString()); + + // Compare canonical forms because IPAddress normalises ("2001:0db8:..." → "2001:db8:..."). + String ipv6 = randomSampleIpv6(); + String canonicalInput = new IPAddressString(ipv6).getAddress().toString(); + assertEquals(canonicalInput, IPUtils.toIPAddress(ipv6).toString()); } @Test @@ -123,12 +142,12 @@ public void isValid() { assertTrue(IPUtils.isValid("::1")); String ipv4 = faker.internet().ipV4Address(); - String ipv6 = faker.internet().ipV6Address().replaceAll("0", ""); + assertTrue(IPUtils.isValid(ipv4), () -> "expected valid IPv4: " + ipv4); - assertTrue(IPUtils.isValid(ipv4)); - assertTrue(IPUtils.isValid(ipv6)); + for (String ipv6 : SAMPLE_IPV6) { + assertTrue(IPUtils.isValid(ipv6), () -> "expected valid IPv6: " + ipv6); + } - // Test invalid IPs assertFalse(IPUtils.isValid("not-an-ip")); assertFalse(IPUtils.isValid("256.256.256.256")); } diff --git a/common/src/test/java/me/confuser/banmanager/common/util/LocaleNormalisationTest.java b/common/src/test/java/me/confuser/banmanager/common/util/LocaleNormalisationTest.java index e88a7a93f..a495f4bb0 100644 --- a/common/src/test/java/me/confuser/banmanager/common/util/LocaleNormalisationTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/LocaleNormalisationTest.java @@ -1,8 +1,8 @@ package me.confuser.banmanager.common.util; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class LocaleNormalisationTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/util/MessageDeferredTest.java b/common/src/test/java/me/confuser/banmanager/common/util/MessageDeferredTest.java index 39152fa04..4d97a94bd 100644 --- a/common/src/test/java/me/confuser/banmanager/common/util/MessageDeferredTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/MessageDeferredTest.java @@ -3,18 +3,18 @@ import me.confuser.banmanager.common.TestLogger; import me.confuser.banmanager.common.TestPlayer; import me.confuser.banmanager.common.kyori.text.Component; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.util.HashMap; import java.util.Map; import java.util.UUID; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class MessageDeferredTest { - @Before + @BeforeEach public void setUp() { MessageRegistry registry = new MessageRegistry("en"); @@ -113,7 +113,7 @@ public void dynamicRegistrationWritesToDefaultLocale() { new Message("custom.key", "Custom message"); String result = Message.getString("custom.key"); - assertNotNull("Dynamic registration should produce a non-null result", result); + assertNotNull(result, "Dynamic registration should produce a non-null result"); assertEquals("Custom message", result); } diff --git a/common/src/test/java/me/confuser/banmanager/common/util/MessageLoadingTest.java b/common/src/test/java/me/confuser/banmanager/common/util/MessageLoadingTest.java index e2a2a96a0..9f42539fc 100644 --- a/common/src/test/java/me/confuser/banmanager/common/util/MessageLoadingTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/MessageLoadingTest.java @@ -4,11 +4,11 @@ import me.confuser.banmanager.common.TestLogger; import me.confuser.banmanager.common.configuration.file.YamlConfiguration; import me.confuser.banmanager.common.kyori.text.Component; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.StringReader; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class MessageLoadingTest extends BasePluginTest { @@ -67,7 +67,7 @@ public void noConsecutiveEmptyLinesInLoadedMessages() { String result = Message.get("test.msg").toString(); for (String line : result.split("\n", -1)) { - assertFalse("Empty lines should contain a space for chat rendering", line.isEmpty()); + assertFalse(line.isEmpty(), "Empty lines should contain a space for chat rendering"); } } } diff --git a/common/src/test/java/me/confuser/banmanager/common/util/MessageRegistryTest.java b/common/src/test/java/me/confuser/banmanager/common/util/MessageRegistryTest.java index 80a123c00..e0a7efa03 100644 --- a/common/src/test/java/me/confuser/banmanager/common/util/MessageRegistryTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/MessageRegistryTest.java @@ -1,19 +1,19 @@ package me.confuser.banmanager.common.util; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.util.HashMap; import java.util.Map; import java.util.Set; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class MessageRegistryTest { private MessageRegistry registry; - @Before + @BeforeEach public void setUp() { registry = new MessageRegistry("en"); diff --git a/common/src/test/java/me/confuser/banmanager/common/util/MessageRendererTest.java b/common/src/test/java/me/confuser/banmanager/common/util/MessageRendererTest.java index c2d20aa2b..a04df5ffc 100644 --- a/common/src/test/java/me/confuser/banmanager/common/util/MessageRendererTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/MessageRendererTest.java @@ -1,25 +1,25 @@ package me.confuser.banmanager.common.util; import me.confuser.banmanager.common.kyori.text.Component; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.util.HashMap; import java.util.Map; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class MessageRendererTest { private MessageRenderer renderer; - @Before + @BeforeEach public void setUp() { renderer = MessageRenderer.getInstance(); } - @After + @AfterEach public void tearDown() { renderer.loadStaticTokens(new HashMap<>()); } @@ -113,6 +113,6 @@ public void escapeTagsPreventsInjection() { String escaped = renderer.escapeTags(malicious); Component result = renderer.render("" + escaped); String plain = renderer.toPlainText(result); - assertTrue("Escaped tags should render as literal text", plain.contains("injected")); + assertTrue(plain.contains("injected"), "Escaped tags should render as literal text"); } } diff --git a/common/src/test/java/me/confuser/banmanager/common/util/MessagesYamlValidatorTest.java b/common/src/test/java/me/confuser/banmanager/common/util/MessagesYamlValidatorTest.java index 2182c1288..faa4d6c50 100644 --- a/common/src/test/java/me/confuser/banmanager/common/util/MessagesYamlValidatorTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/MessagesYamlValidatorTest.java @@ -5,9 +5,9 @@ import me.confuser.banmanager.common.kyori.text.Component; import me.confuser.banmanager.common.kyori.text.minimessage.tag.resolver.Placeholder; import me.confuser.banmanager.common.kyori.text.minimessage.tag.resolver.TagResolver; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.io.InputStream; import java.io.InputStreamReader; @@ -22,9 +22,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; /** * Validates that every message in the bundled messages_en.yml parses cleanly through MiniMessage. @@ -50,7 +50,7 @@ public class MessagesYamlValidatorTest { private MessageRenderer renderer; private List errors; - @Before + @BeforeEach public void setUp() { MessageRenderer.reset(); renderer = MessageRenderer.getInstance(); @@ -62,7 +62,7 @@ public void setUp() { errors = new ArrayList<>(); } - @After + @AfterEach public void tearDown() { renderer.loadStaticTokens(new HashMap<>()); MessageRenderer.reset(); @@ -72,7 +72,7 @@ public void tearDown() { public void everyMessageParsesWithoutError() throws Exception { YamlConfiguration conf = loadBundledMessages(); ConfigurationSection messages = conf.getConfigurationSection("messages"); - assertNotNull("messages section missing", messages); + assertNotNull(messages, "messages section missing"); TagResolver.Builder resolverBuilder = TagResolver.builder(); for (String token : KNOWN_DYNAMIC_TOKENS) { @@ -107,7 +107,7 @@ public void everyMessageParsesWithoutError() throws Exception { if (!errors.isEmpty()) { fail("Found " + errors.size() + " message issue(s):\n" + String.join("\n", errors)); } - assertTrue("Expected to parse at least 1 message", parsed > 0); + assertTrue(parsed > 0, "Expected to parse at least 1 message"); } @Test @@ -203,17 +203,14 @@ public void colorChoiceIsConsistentForActionButtons() throws Exception { String close = messages.getString("report.actions.close"); String tp = messages.getString("report.actions.tp"); - assertNotNull("report.actions.assign missing", assign); - assertNotNull("report.actions.close missing", close); - assertNotNull("report.actions.tp missing", tp); + assertNotNull(assign, "report.actions.assign missing"); + assertNotNull(close, "report.actions.close missing"); + assertNotNull(tp, "report.actions.tp missing"); String buttonColor = ""; - assertTrue("report.actions.assign should use " + buttonColor + " for visual consistency: " + assign, - assign.contains(buttonColor)); - assertTrue("report.actions.close should use " + buttonColor + " for visual consistency: " + close, - close.contains(buttonColor)); - assertTrue("report.actions.tp should use " + buttonColor + " for visual consistency: " + tp, - tp.contains(buttonColor)); + assertTrue(assign.contains(buttonColor), "report.actions.assign should use " + buttonColor + " for visual consistency: " + assign); + assertTrue(close.contains(buttonColor), "report.actions.close should use " + buttonColor + " for visual consistency: " + close); + assertTrue(tp.contains(buttonColor), "report.actions.tp should use " + buttonColor + " for visual consistency: " + tp); } @Test @@ -221,8 +218,7 @@ public void noTypoMissingNoun_addnoteall() throws Exception { YamlConfiguration conf = loadBundledMessages(); String value = conf.getString("messages.addnoteall.notify"); assertNotNull(value); - assertTrue("addnoteall.notify is missing the word 'note': " + value, - value.toLowerCase().contains("note")); + assertTrue(value.toLowerCase().contains("note"), "addnoteall.notify is missing the word 'note': " + value); } @Test @@ -230,8 +226,7 @@ public void noGrammarErrors_invalidReason() throws Exception { YamlConfiguration conf = loadBundledMessages(); String value = conf.getString("messages.sender.error.invalidReason"); assertNotNull(value); - assertTrue("invalidReason should say 'is not a valid reason' (was previously 'is no valid reason'): " + value, - value.contains("is not a valid")); + assertTrue(value.contains("is not a valid"), "invalidReason should say 'is not a valid reason' (was previously 'is no valid reason'): " + value); } @Test @@ -240,14 +235,12 @@ public void banPlayerKickAndDisallowedShareCriticalTokens() throws Exception { String disallowed = conf.getString("messages.ban.player.disallowed"); String kick = conf.getString("messages.ban.player.kick"); - assertNotNull("ban.player.disallowed missing", disallowed); - assertNotNull("ban.player.kick missing", kick); + assertNotNull(disallowed, "ban.player.disallowed missing"); + assertNotNull(kick, "ban.player.kick missing"); for (String token : new String[]{"", "", "", ""}) { - assertTrue("ban.player.disallowed should contain " + token + ": " + disallowed, - disallowed.contains(token)); - assertTrue("ban.player.kick should contain " + token + " for parity with disallowed: " + kick, - kick.contains(token)); + assertTrue(disallowed.contains(token), "ban.player.disallowed should contain " + token + ": " + disallowed); + assertTrue(kick.contains(token), "ban.player.kick should contain " + token + " for parity with disallowed: " + kick); } } @@ -257,14 +250,12 @@ public void tempbanPlayerKickAndDisallowedShareCriticalTokens() throws Exception String disallowed = conf.getString("messages.tempban.player.disallowed"); String kick = conf.getString("messages.tempban.player.kick"); - assertNotNull("tempban.player.disallowed missing", disallowed); - assertNotNull("tempban.player.kick missing", kick); + assertNotNull(disallowed, "tempban.player.disallowed missing"); + assertNotNull(kick, "tempban.player.kick missing"); for (String token : new String[]{"", "", "", "", ""}) { - assertTrue("tempban.player.disallowed should contain " + token + ": " + disallowed, - disallowed.contains(token)); - assertTrue("tempban.player.kick should contain " + token + " for parity with disallowed: " + kick, - kick.contains(token)); + assertTrue(disallowed.contains(token), "tempban.player.disallowed should contain " + token + ": " + disallowed); + assertTrue(kick.contains(token), "tempban.player.kick should contain " + token + " for parity with disallowed: " + kick); } } @@ -276,8 +267,7 @@ public void dashboardHeaderRendersStaffDashboardText() throws Exception { Component component = renderer.render(header); String plain = renderer.toPlainText(component); - assertTrue("dashboard.header plain text should contain 'Staff Dashboard': " + plain, - plain.contains("Staff Dashboard")); + assertTrue(plain.contains("Staff Dashboard"), "dashboard.header plain text should contain 'Staff Dashboard': " + plain); } @Test @@ -311,7 +301,7 @@ public void noLeftoverBracketTokens() throws Exception { private YamlConfiguration loadBundledMessages() throws Exception { InputStream in = getClass().getClassLoader().getResourceAsStream(MESSAGES_RESOURCE); - assertNotNull("Resource " + MESSAGES_RESOURCE + " not found on classpath", in); + assertNotNull(in, "Resource " + MESSAGES_RESOURCE + " not found on classpath"); try (InputStream stream = in; Reader reader = new InputStreamReader(stream)) { return YamlConfiguration.loadConfiguration(reader); diff --git a/common/src/test/java/me/confuser/banmanager/common/util/PaginatedViewTest.java b/common/src/test/java/me/confuser/banmanager/common/util/PaginatedViewTest.java index b79bac6d9..660c76182 100644 --- a/common/src/test/java/me/confuser/banmanager/common/util/PaginatedViewTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/PaginatedViewTest.java @@ -1,12 +1,12 @@ package me.confuser.banmanager.common.util; import me.confuser.banmanager.common.kyori.text.Component; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; public class PaginatedViewTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/util/SchedulerTimeTest.java b/common/src/test/java/me/confuser/banmanager/common/util/SchedulerTimeTest.java index dfa5a97f7..5c9dd24b8 100644 --- a/common/src/test/java/me/confuser/banmanager/common/util/SchedulerTimeTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/SchedulerTimeTest.java @@ -1,10 +1,10 @@ package me.confuser.banmanager.common.util; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.time.Duration; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Tests for SchedulerTime utility class. @@ -15,68 +15,68 @@ public class SchedulerTimeTest { @Test public void negativeDurationReturnsZero() { Duration negative = Duration.ofMillis(-1); - assertEquals("Negative duration should return 0 ticks", 0, SchedulerTime.durationToTicksCeil(negative)); + assertEquals(0, SchedulerTime.durationToTicksCeil(negative), "Negative duration should return 0 ticks"); } @Test public void zeroDurationReturnsZero() { Duration zero = Duration.ZERO; - assertEquals("Zero duration should return 0 ticks", 0, SchedulerTime.durationToTicksCeil(zero)); + assertEquals(0, SchedulerTime.durationToTicksCeil(zero), "Zero duration should return 0 ticks"); } @Test public void oneMillisecondReturnsOneTick() { // 1ms should ceil to 1 tick (since 1ms > 0, it needs at least 1 tick) Duration oneMs = Duration.ofMillis(1); - assertEquals("1ms should ceil to 1 tick", 1, SchedulerTime.durationToTicksCeil(oneMs)); + assertEquals(1, SchedulerTime.durationToTicksCeil(oneMs), "1ms should ceil to 1 tick"); } @Test public void fortyNineMillisecondsReturnsOneTick() { // 49ms should ceil to 1 tick Duration ms49 = Duration.ofMillis(49); - assertEquals("49ms should ceil to 1 tick", 1, SchedulerTime.durationToTicksCeil(ms49)); + assertEquals(1, SchedulerTime.durationToTicksCeil(ms49), "49ms should ceil to 1 tick"); } @Test public void fiftyMillisecondsReturnsOneTick() { // 50ms = exactly 1 tick Duration ms50 = Duration.ofMillis(50); - assertEquals("50ms should equal 1 tick", 1, SchedulerTime.durationToTicksCeil(ms50)); + assertEquals(1, SchedulerTime.durationToTicksCeil(ms50), "50ms should equal 1 tick"); } @Test public void fiftyOneMillisecondsReturnsTwoTicks() { // 51ms should ceil to 2 ticks Duration ms51 = Duration.ofMillis(51); - assertEquals("51ms should ceil to 2 ticks", 2, SchedulerTime.durationToTicksCeil(ms51)); + assertEquals(2, SchedulerTime.durationToTicksCeil(ms51), "51ms should ceil to 2 ticks"); } @Test public void nineHundredNinetyNineMillisecondsReturnsTwentyTicks() { // 999ms should ceil to 20 ticks (999 + 49 = 1048, 1048 / 50 = 20.96 -> 20) Duration ms999 = Duration.ofMillis(999); - assertEquals("999ms should ceil to 20 ticks", 20, SchedulerTime.durationToTicksCeil(ms999)); + assertEquals(20, SchedulerTime.durationToTicksCeil(ms999), "999ms should ceil to 20 ticks"); } @Test public void oneSecondReturnsTwentyTicks() { // 1000ms = exactly 20 ticks Duration oneSecond = Duration.ofSeconds(1); - assertEquals("1 second should equal 20 ticks", 20, SchedulerTime.durationToTicksCeil(oneSecond)); + assertEquals(20, SchedulerTime.durationToTicksCeil(oneSecond), "1 second should equal 20 ticks"); } @Test public void oneSecondAndOneMillisReturnsTwentyOneTicks() { // 1001ms should ceil to 21 ticks Duration ms1001 = Duration.ofMillis(1001); - assertEquals("1001ms should ceil to 21 ticks", 21, SchedulerTime.durationToTicksCeil(ms1001)); + assertEquals(21, SchedulerTime.durationToTicksCeil(ms1001), "1001ms should ceil to 21 ticks"); } @Test public void fiveSecondsReturnsOneHundredTicks() { // 5000ms = 100 ticks Duration fiveSeconds = Duration.ofSeconds(5); - assertEquals("5 seconds should equal 100 ticks", 100, SchedulerTime.durationToTicksCeil(fiveSeconds)); + assertEquals(100, SchedulerTime.durationToTicksCeil(fiveSeconds), "5 seconds should equal 100 ticks"); } } diff --git a/common/src/test/java/me/confuser/banmanager/common/util/StringUtilsTest.java b/common/src/test/java/me/confuser/banmanager/common/util/StringUtilsTest.java index f502f3330..7668d19fc 100755 --- a/common/src/test/java/me/confuser/banmanager/common/util/StringUtilsTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/StringUtilsTest.java @@ -1,8 +1,8 @@ package me.confuser.banmanager.common.util; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.*; // From apache commons lang3 public class StringUtilsTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/util/parsers/InfoCommandParserTest.java b/common/src/test/java/me/confuser/banmanager/common/util/parsers/InfoCommandParserTest.java index f6f39c4a6..814fe4443 100644 --- a/common/src/test/java/me/confuser/banmanager/common/util/parsers/InfoCommandParserTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/parsers/InfoCommandParserTest.java @@ -1,9 +1,9 @@ package me.confuser.banmanager.common.util.parsers; import me.confuser.banmanager.common.BasePluginTest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class InfoCommandParserTest extends BasePluginTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/util/parsers/UnbanCommandParserTest.java b/common/src/test/java/me/confuser/banmanager/common/util/parsers/UnbanCommandParserTest.java index c36f4f512..e8ad97fcd 100644 --- a/common/src/test/java/me/confuser/banmanager/common/util/parsers/UnbanCommandParserTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/parsers/UnbanCommandParserTest.java @@ -1,9 +1,9 @@ package me.confuser.banmanager.common.util.parsers; import me.confuser.banmanager.common.BasePluginTest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class UnbanCommandParserTest extends BasePluginTest { diff --git a/common/src/test/java/me/confuser/banmanager/common/util/parsers/WarnCommandParserTest.java b/common/src/test/java/me/confuser/banmanager/common/util/parsers/WarnCommandParserTest.java index e0b64c722..8144c0a7b 100644 --- a/common/src/test/java/me/confuser/banmanager/common/util/parsers/WarnCommandParserTest.java +++ b/common/src/test/java/me/confuser/banmanager/common/util/parsers/WarnCommandParserTest.java @@ -1,9 +1,9 @@ package me.confuser.banmanager.common.util.parsers; import me.confuser.banmanager.common.BasePluginTest; -import org.junit.Test; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class WarnCommandParserTest extends BasePluginTest { diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index e86f86de7..a4807145f 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -169,16 +169,25 @@ tasks.named("shadowJar") { include(dependency(":BanManagerCommon")) include(dependency(":BanManagerLibs")) } + + mergeServiceFiles() + exclude("GradleStart**") exclude(".cache"); exclude("LICENSE*") - exclude("META-INF/services/**") exclude("META-INF/maven/**") + // BanManagerSlf4jServiceProvider only ships in (and is relocated by) Bukkit. + // Minecraft / Fabric provide their own SLF4J 2.x implementation, so removing + // the bundled provider entry avoids a ServiceConfigurationError at server + // bootstrap (LogUtils initialises SLF4J before BanManager's mod loads). + exclude("META-INF/services/org.slf4j.spi.SLF4JServiceProvider") exclude("org/intellij/**") exclude("org/jetbrains/**") exclude("/mappings/*") - minimize() + minimize { + exclude(dependency(":BanManagerLibs")) + } } tasks.named("remapJar") { diff --git a/fabric/src/main/java/me/confuser/banmanager/fabric/listeners/WebhookListener.java b/fabric/src/main/java/me/confuser/banmanager/fabric/listeners/WebhookListener.java index 994ffed05..8b1d0fd7d 100644 --- a/fabric/src/main/java/me/confuser/banmanager/fabric/listeners/WebhookListener.java +++ b/fabric/src/main/java/me/confuser/banmanager/fabric/listeners/WebhookListener.java @@ -2,7 +2,7 @@ import me.confuser.banmanager.common.BanManagerPlugin; import me.confuser.banmanager.common.listeners.CommonWebhookListener; -import me.confuser.banmanager.common.listeners.CommonWebhookListener.WebhookData; +import me.confuser.banmanager.common.data.Webhook; import me.confuser.banmanager.common.util.Message; import me.confuser.banmanager.fabric.BanManagerEvents; import me.confuser.banmanager.common.data.*; @@ -28,54 +28,54 @@ public WebhookListener(BanManagerPlugin plugin) { } private void notifyOnBan(PlayerBanData banData, boolean silent, Message kickMessage) { - List webhooks = listener.notifyOnBan(banData); + List webhooks = listener.notifyOnBan(banData); sendAll(webhooks, silent); } private void notifyOnMute(PlayerMuteData muteData, boolean silent) { - List webhooks = listener.notifyOnMute(muteData); + List webhooks = listener.notifyOnMute(muteData); sendAll(webhooks, silent); } private void notifyOnBan(IpBanData banData, boolean silent) { - List webhooks = listener.notifyOnBan(banData); + List webhooks = listener.notifyOnBan(banData); sendAll(webhooks, silent); } private void notifyOnKick(PlayerKickData kickData, boolean silent) { - List webhooks = listener.notifyOnKick(kickData); + List webhooks = listener.notifyOnKick(kickData); sendAll(webhooks, silent); } private void notifyOnWarn(PlayerWarnData warnData, boolean silent) { - List webhooks = listener.notifyOnWarn(warnData); + List webhooks = listener.notifyOnWarn(warnData); sendAll(webhooks, silent); } private void notifyOnUnban(PlayerBanData banData, PlayerData actor, String reason, boolean silent) { - List webhooks = listener.notifyOnUnban(banData, actor, reason); + List webhooks = listener.notifyOnUnban(banData, actor, reason); sendAll(webhooks, silent); } private void notifyOnUnban(IpBanData banData, PlayerData actor, String reason, boolean silent) { - List webhooks = listener.notifyOnUnban(banData, actor, reason); + List webhooks = listener.notifyOnUnban(banData, actor, reason); sendAll(webhooks, silent); } private void notifyOnUnmute(PlayerMuteData muteData, PlayerData actor, String reason, boolean silent) { - List webhooks = listener.notifyOnUnmute(muteData, actor, reason); + List webhooks = listener.notifyOnUnmute(muteData, actor, reason); sendAll(webhooks, silent); } private void notifyOnReport(PlayerReportData reportData, boolean silent) { - List webhooks = listener.notifyOnReport(reportData, reportData.getActor(), reportData.getReason()); + List webhooks = listener.notifyOnReport(reportData, reportData.getActor(), reportData.getReason()); sendAll(webhooks, silent); } - private void sendAll(List webhooks, boolean isSilent) { - for (WebhookData data : webhooks) { - if (isSilent && data.ignoreSilent) continue; - if (data.url == null || data.payload == null || data.url.isEmpty() || data.payload.isEmpty()) continue; + private void sendAll(List webhooks, boolean isSilent) { + for (Webhook data : webhooks) { + if (isSilent && data.ignoreSilent()) continue; + if (data.url() == null || data.payload() == null || data.url().isEmpty() || data.payload().isEmpty()) continue; listener.sendAsync(data); } } diff --git a/gradle.properties b/gradle.properties index 79a0ef2cb..321afbf96 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,4 +3,4 @@ version=8.0.0-SNAPSHOT org.gradle.parallel=true description="The defacto plugin for Minecraft to manage punishments and moderate more effectively" -org.gradle.jvmargs=-Xmx2G +org.gradle.jvmargs=-Xmx2G -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+UseStringDeduplication diff --git a/libs/build.gradle.kts b/libs/build.gradle.kts index 47058d1e5..cf3dcabc6 100644 --- a/libs/build.gradle.kts +++ b/libs/build.gradle.kts @@ -14,22 +14,22 @@ dependencies { "shade"("net.kyori:examination-string:1.3.0") "shade"("net.kyori:option:1.1.0") - "shade"("com.j256.ormlite:ormlite-core:5.1") - "shade"("com.j256.ormlite:ormlite-jdbc:5.1") + "shade"("com.j256.ormlite:ormlite-core:6.1") + "shade"("com.j256.ormlite:ormlite-jdbc:6.1") - "shade"("com.zaxxer:HikariCP:4.0.3") - "shade"("org.mariadb.jdbc:mariadb-java-client:2.7.4") - "shade"("mysql:mysql-connector-java:8.0.27") + "shade"("com.zaxxer:HikariCP:6.3.3") + "shade"("org.mariadb.jdbc:mariadb-java-client:3.5.7") + "shade"("com.mysql:mysql-connector-j:8.4.0") "shade"("com.googlecode.concurrent-trees:concurrent-trees:2.4.0") "shade"("com.maxmind.db:maxmind-db-gson:2.0.3") - "shade"("org.yaml:snakeyaml:1.29") - "shade"("com.google.code.gson:gson:2.3.1") + "shade"("org.yaml:snakeyaml:2.4") + "shade"("com.google.code.gson:gson:2.11.0") "shade"("com.github.spullara.cli-parser:cli-parser:1.1.5") - "shade"("com.google.guava:guava:21.0") + "shade"("com.google.guava:guava:33.4.8-jre") - "shade"("org.apache.commons:commons-compress:1.19") - "shade"("com.github.seancfoley:ipaddress:5.3.4") + "shade"("org.apache.commons:commons-compress:1.27.1") + "shade"("com.github.seancfoley:ipaddress:5.5.1") "shade"("com.h2database:h2:1.4.200") } @@ -74,8 +74,8 @@ tasks.named("jar") { } relocate("com.j256.ormlite", "me.confuser.banmanager.common.ormlite") { - include(dependency("com.j256.ormlite:ormlite-core:5.1")) - include(dependency("com.j256.ormlite:ormlite-jdbc:5.1")) + include(dependency("com.j256.ormlite:ormlite-core")) + include(dependency("com.j256.ormlite:ormlite-jdbc")) } relocate("com.zaxxer.hikari", "me.confuser.banmanager.common.hikari") { @@ -87,7 +87,7 @@ tasks.named("jar") { } relocate("com.mysql", "me.confuser.banmanager.common.mysql") { - include(dependency("mysql:mysql-connector-java")) + include(dependency("com.mysql:mysql-connector-j")) } relocate("com.google.gson", "me.confuser.banmanager.common.gson") { @@ -119,10 +119,16 @@ tasks.named("jar") { } } + // MariaDB Connector/J 3.x, MySQL Connector/J 8.x, HikariCP and others + // discover codecs / credential plugins / drivers via ServiceLoader. Keep + // META-INF/services and let the shadow task merge + relocate the entries + // alongside the package renames (e.g. org.mariadb.jdbc.plugin.codec.* -> + // me.confuser.banmanager.common.mariadb.plugin.codec.*). + mergeServiceFiles() + exclude("GradleStart**") exclude(".cache"); exclude("LICENSE*") - exclude("META-INF/services/**") exclude("META-INF/maven/**") exclude("org/intellij/**") exclude("org/jetbrains/**") diff --git a/sponge/build.gradle.kts b/sponge/build.gradle.kts index c126d65da..9e43cbe1f 100644 --- a/sponge/build.gradle.kts +++ b/sponge/build.gradle.kts @@ -92,7 +92,7 @@ dependencies { api(project(":BanManagerCommon")) { isTransitive = true } - "shadeOnly"("org.bstats:bstats-sponge:3.0.2") + "shadeOnly"("org.bstats:bstats-sponge:3.2.1") } // Sponge API 11+ requires Java 21 @@ -138,11 +138,16 @@ tasks.named("shadowJar") { relocate("org.bstats", "me.confuser.banmanager.common.bstats") } + mergeServiceFiles() + exclude("GradleStart**") exclude(".cache"); exclude("LICENSE*") - exclude("META-INF/services/**") exclude("META-INF/maven/**") + // BanManagerSlf4jServiceProvider only ships in (and is relocated by) Bukkit. + // Sponge provides its own SLF4J 2.x implementation, so removing the + // bundled provider entry avoids a ServiceConfigurationError at startup. + exclude("META-INF/services/org.slf4j.spi.SLF4JServiceProvider") exclude("META-INF/versions/**") exclude("org/intellij/**") exclude("org/jetbrains/**") @@ -153,6 +158,7 @@ tasks.named("shadowJar") { minimize { exclude(dependency("org.bstats:.*:.*")) + exclude(dependency(":BanManagerLibs")) } } diff --git a/sponge/src/main/java/me/confuser/banmanager/sponge/listeners/WebhookListener.java b/sponge/src/main/java/me/confuser/banmanager/sponge/listeners/WebhookListener.java index a2773905b..02b1d11cd 100644 --- a/sponge/src/main/java/me/confuser/banmanager/sponge/listeners/WebhookListener.java +++ b/sponge/src/main/java/me/confuser/banmanager/sponge/listeners/WebhookListener.java @@ -2,7 +2,7 @@ import me.confuser.banmanager.common.BanManagerPlugin; import me.confuser.banmanager.common.listeners.CommonWebhookListener; -import me.confuser.banmanager.common.listeners.CommonWebhookListener.WebhookData; +import me.confuser.banmanager.common.data.Webhook; import me.confuser.banmanager.sponge.api.events.*; import org.spongepowered.api.event.Listener; import org.spongepowered.api.event.Order; @@ -18,62 +18,62 @@ public WebhookListener(BanManagerPlugin plugin) { @Listener(order = Order.POST) public void notifyOnBan(PlayerBannedEvent event) { - List webhooks = listener.notifyOnBan(event.getBan()); + List webhooks = listener.notifyOnBan(event.getBan()); sendAll(webhooks, event.isSilent()); } @Listener(order = Order.POST) public void notifyOnMute(PlayerMutedEvent event) { - List webhooks = listener.notifyOnMute(event.getMute()); + List webhooks = listener.notifyOnMute(event.getMute()); sendAll(webhooks, event.isSilent()); } @Listener(order = Order.POST) public void notifyOnWarn(PlayerWarnedEvent event) { - List webhooks = listener.notifyOnWarn(event.getWarning()); + List webhooks = listener.notifyOnWarn(event.getWarning()); sendAll(webhooks, event.isSilent()); } @Listener(order = Order.POST) public void notifyOnBan(IpBannedEvent event) { - List webhooks = listener.notifyOnBan(event.getBan()); + List webhooks = listener.notifyOnBan(event.getBan()); sendAll(webhooks, event.isSilent()); } @Listener(order = Order.POST) public void notifyOnKick(PlayerKickedEvent event) { - List webhooks = listener.notifyOnKick(event.getKick()); + List webhooks = listener.notifyOnKick(event.getKick()); sendAll(webhooks, event.isSilent()); } @Listener(order = Order.POST) public void notifyOnUnban(PlayerUnbanEvent event) { - List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); + List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); sendAll(webhooks, event.isSilent()); } @Listener(order = Order.POST) public void notifyOnUnban(IpUnbanEvent event) { - List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); + List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); sendAll(webhooks, event.isSilent()); } @Listener(order = Order.POST) public void notifyOnUnmute(PlayerUnmuteEvent event) { - List webhooks = listener.notifyOnUnmute(event.getMute(), event.getActor(), event.getReason()); + List webhooks = listener.notifyOnUnmute(event.getMute(), event.getActor(), event.getReason()); sendAll(webhooks, event.isSilent()); } @Listener(order = Order.POST) public void notifyOnReport(PlayerReportedEvent event) { - List webhooks = listener.notifyOnReport(event.getReport(), event.getReport().getActor(), event.getReport().getReason()); + List webhooks = listener.notifyOnReport(event.getReport(), event.getReport().getActor(), event.getReport().getReason()); sendAll(webhooks, event.isSilent()); } - private void sendAll(List webhooks, boolean isSilent) { - for (WebhookData data : webhooks) { - if (isSilent && data.ignoreSilent) continue; - if (data.url == null || data.payload == null || data.url.isEmpty() || data.payload.isEmpty()) continue; + private void sendAll(List webhooks, boolean isSilent) { + for (Webhook data : webhooks) { + if (isSilent && data.ignoreSilent()) continue; + if (data.url() == null || data.payload() == null || data.url().isEmpty() || data.payload().isEmpty()) continue; listener.sendAsync(data); } } diff --git a/velocity/build.gradle.kts b/velocity/build.gradle.kts index 68c26abd7..8168bd78e 100644 --- a/velocity/build.gradle.kts +++ b/velocity/build.gradle.kts @@ -65,7 +65,7 @@ dependencies { api(project(":BanManagerCommon")) compileOnly("com.velocitypowered:velocity-api:3.1.0") annotationProcessor("com.velocitypowered:velocity-api:3.1.0") - "shadeOnly"("org.bstats:bstats-velocity:3.0.0") + "shadeOnly"("org.bstats:bstats-velocity:3.2.1") } tasks.named("processResources") { @@ -96,16 +96,23 @@ tasks.named("shadowJar") { relocate("org.bstats", "me.confuser.banmanager.common.bstats") } + + mergeServiceFiles() + exclude("GradleStart**") exclude(".cache") exclude("LICENSE*") - exclude("META-INF/services/**") exclude("META-INF/maven/**") + // BanManagerSlf4jServiceProvider only ships in (and is relocated by) Bukkit. + // Velocity provides its own SLF4J 2.x implementation, so removing the + // bundled provider entry avoids a ServiceConfigurationError at startup. + exclude("META-INF/services/org.slf4j.spi.SLF4JServiceProvider") exclude("org/intellij/**") exclude("org/jetbrains/**") minimize { exclude(dependency("org.bstats:.*:.*")) + exclude(dependency(":BanManagerLibs")) } } diff --git a/velocity/src/main/java/me/confuser/banmanager/velocity/listeners/WebhookListener.java b/velocity/src/main/java/me/confuser/banmanager/velocity/listeners/WebhookListener.java index 9d6f1f531..3e37b287b 100644 --- a/velocity/src/main/java/me/confuser/banmanager/velocity/listeners/WebhookListener.java +++ b/velocity/src/main/java/me/confuser/banmanager/velocity/listeners/WebhookListener.java @@ -4,7 +4,7 @@ import me.confuser.banmanager.velocity.Listener; import me.confuser.banmanager.common.BanManagerPlugin; import me.confuser.banmanager.common.listeners.CommonWebhookListener; -import me.confuser.banmanager.common.listeners.CommonWebhookListener.WebhookData; +import me.confuser.banmanager.common.data.Webhook; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.PostOrder; @@ -19,62 +19,62 @@ public WebhookListener(BanManagerPlugin plugin) { @Subscribe(order = PostOrder.LAST) public void notifyOnBan(PlayerBannedEvent event) { - List webhooks = listener.notifyOnBan(event.getBan()); + List webhooks = listener.notifyOnBan(event.getBan()); sendAll(webhooks, event.isSilent()); } @Subscribe(order = PostOrder.LAST) public void notifyOnMute(PlayerMutedEvent event) { - List webhooks = listener.notifyOnMute(event.getMute()); + List webhooks = listener.notifyOnMute(event.getMute()); sendAll(webhooks, event.isSilent()); } @Subscribe(order = PostOrder.LAST) public void notifyOnBan(IpBannedEvent event) { - List webhooks = listener.notifyOnBan(event.getBan()); + List webhooks = listener.notifyOnBan(event.getBan()); sendAll(webhooks, event.isSilent()); } @Subscribe(order = PostOrder.LAST) public void notifyOnKick(PlayerKickedEvent event) { - List webhooks = listener.notifyOnKick(event.getKick()); + List webhooks = listener.notifyOnKick(event.getKick()); sendAll(webhooks, event.isSilent()); } @Subscribe(order = PostOrder.LAST) public void notifyOnWarn(PlayerWarnedEvent event) { - List webhooks = listener.notifyOnWarn(event.getWarning()); + List webhooks = listener.notifyOnWarn(event.getWarning()); sendAll(webhooks, event.isSilent()); } @Subscribe(order = PostOrder.LAST) public void notifyOnUnban(PlayerUnbanEvent event) { - List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); + List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); sendAll(webhooks, event.isSilent()); } @Subscribe(order = PostOrder.LAST) public void notifyOnUnban(IpUnbanEvent event) { - List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); + List webhooks = listener.notifyOnUnban(event.getBan(), event.getActor(), event.getReason()); sendAll(webhooks, event.isSilent()); } @Subscribe(order = PostOrder.LAST) public void notifyOnUnmute(PlayerUnmuteEvent event) { - List webhooks = listener.notifyOnUnmute(event.getMute(), event.getActor(), event.getReason()); + List webhooks = listener.notifyOnUnmute(event.getMute(), event.getActor(), event.getReason()); sendAll(webhooks, event.isSilent()); } @Subscribe(order = PostOrder.LAST) public void notifyOnReport(PlayerReportedEvent event) { - List webhooks = listener.notifyOnReport(event.getReport(), event.getReport().getActor(), event.getReport().getReason()); + List webhooks = listener.notifyOnReport(event.getReport(), event.getReport().getActor(), event.getReport().getReason()); sendAll(webhooks, event.isSilent()); } - private void sendAll(List webhooks, boolean isSilent) { - for (WebhookData data : webhooks) { - if (isSilent && data.ignoreSilent) continue; - if (data.url == null || data.payload == null || data.url.isEmpty() || data.payload.isEmpty()) continue; + private void sendAll(List webhooks, boolean isSilent) { + for (Webhook data : webhooks) { + if (isSilent && data.ignoreSilent()) continue; + if (data.url() == null || data.payload() == null || data.url().isEmpty() || data.payload().isEmpty()) continue; listener.sendAsync(data); } }