diff options
| author | Sho Sakuma <me@m1sk9.dev> | 2026-02-26 00:20:33 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-26 00:20:33 +0900 |
| commit | 382ccbc765cd1855d688f60f1235f3f4bfaac9d8 (patch) | |
| tree | 2bb41b90c19cfd3cfbe638f9f8fbd420ab96aa86 /platform-velocity | |
| parent | 56ed04185036635dcfd2763391cd64b8be371b1a (diff) | |
| parent | 70c785eee4c61601ba7fffa17cc8b992b4793491 (diff) | |
| download | LunaticChat-382ccbc765cd1855d688f60f1235f3f4bfaac9d8.tar.gz LunaticChat-382ccbc765cd1855d688f60f1235f3f4bfaac9d8.tar.bz2 LunaticChat-382ccbc765cd1855d688f60f1235f3f4bfaac9d8.zip | |
Merge pull request #119 from m1sk9/feat/codecov-jacoco-integration
feat: add Codecov/Jacoco integration and expand test coverage
Diffstat (limited to 'platform-velocity')
2 files changed, 347 insertions, 0 deletions
diff --git a/platform-velocity/src/test/kotlin/dev/m1sk9/lunaticChat/velocity/messaging/CrossServerChatRelayTest.kt b/platform-velocity/src/test/kotlin/dev/m1sk9/lunaticChat/velocity/messaging/CrossServerChatRelayTest.kt new file mode 100644 index 0000000..50b0db2 --- /dev/null +++ b/platform-velocity/src/test/kotlin/dev/m1sk9/lunaticChat/velocity/messaging/CrossServerChatRelayTest.kt @@ -0,0 +1,136 @@ +package dev.m1sk9.lunaticChat.velocity.messaging + +import com.velocitypowered.api.proxy.ProxyServer +import com.velocitypowered.api.proxy.messages.ChannelIdentifier +import com.velocitypowered.api.proxy.server.RegisteredServer +import dev.m1sk9.lunaticChat.engine.protocol.PluginMessage +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.slf4j.Logger +import kotlin.test.Test + +class CrossServerChatRelayTest { + private fun createRelay(): Triple<CrossServerChatRelay, ProxyServer, Logger> { + val server = mockk<ProxyServer>(relaxed = true) + val logger = mockk<Logger>(relaxed = true) + val relay = CrossServerChatRelay(server, logger) + return Triple(relay, server, logger) + } + + private fun createRegisteredServer(name: String): RegisteredServer { + val server = mockk<RegisteredServer>(relaxed = true) + val serverInfo = mockk<com.velocitypowered.api.proxy.server.ServerInfo>(relaxed = true) + every { serverInfo.name } returns name + every { server.serverInfo } returns serverInfo + return server + } + + private fun createTestMessage( + messageId: String = "msg-1", + serverName: String = "lobby", + ): PluginMessage.GlobalChatMessage = + PluginMessage.GlobalChatMessage( + messageId = messageId, + serverName = serverName, + playerId = "00000001-0000-0000-0000-000000000000", + playerName = "TestPlayer", + message = "Hello!", + timestamp = 1000L, + ) + + @Test + fun `relayGlobalMessage should exclude source server`() { + val (relay, proxyServer, _) = createRelay() + val sourceServer = createRegisteredServer("lobby") + val targetServer = createRegisteredServer("survival") + + every { proxyServer.allServers } returns listOf(sourceServer, targetServer) + + relay.relayGlobalMessage(createTestMessage(), sourceServer) + + verify(exactly = 1) { targetServer.sendPluginMessage(any<ChannelIdentifier>(), any<ByteArray>()) } + verify(exactly = 0) { sourceServer.sendPluginMessage(any<ChannelIdentifier>(), any<ByteArray>()) } + } + + @Test + fun `relayGlobalMessage should relay to multiple servers`() { + val (relay, proxyServer, _) = createRelay() + val sourceServer = createRegisteredServer("lobby") + val target1 = createRegisteredServer("survival") + val target2 = createRegisteredServer("creative") + + every { proxyServer.allServers } returns listOf(sourceServer, target1, target2) + + relay.relayGlobalMessage(createTestMessage(), sourceServer) + + verify(exactly = 1) { target1.sendPluginMessage(any<ChannelIdentifier>(), any<ByteArray>()) } + verify(exactly = 1) { target2.sendPluginMessage(any<ChannelIdentifier>(), any<ByteArray>()) } + } + + @Test + fun `relayGlobalMessage with only source server should relay to zero`() { + val (relay, proxyServer, logger) = createRelay() + val sourceServer = createRegisteredServer("lobby") + + every { proxyServer.allServers } returns listOf(sourceServer) + + relay.relayGlobalMessage(createTestMessage(), sourceServer) + + verify(exactly = 0) { sourceServer.sendPluginMessage(any<ChannelIdentifier>(), any<ByteArray>()) } + verify { logger.info(match { it.contains("0 servers") }) } + } + + @Test + fun `relayGlobalMessage should log with messageId and playerName`() { + val (relay, proxyServer, logger) = createRelay() + val sourceServer = createRegisteredServer("lobby") + val targetServer = createRegisteredServer("survival") + + every { proxyServer.allServers } returns listOf(sourceServer, targetServer) + + val message = createTestMessage(messageId = "test-msg-123") + relay.relayGlobalMessage(message, sourceServer) + + verify { + logger.info( + match { msg -> + msg.contains("test-msg-123") && msg.contains("TestPlayer") + }, + ) + } + } + + @Test + fun `relayGlobalMessage should log error on exception`() { + val (relay, proxyServer, logger) = createRelay() + val sourceServer = createRegisteredServer("lobby") + val targetServer = createRegisteredServer("survival") + + every { proxyServer.allServers } returns listOf(sourceServer, targetServer) + every { targetServer.sendPluginMessage(any<ChannelIdentifier>(), any<ByteArray>()) } throws + RuntimeException("connection failed") + + relay.relayGlobalMessage(createTestMessage(), sourceServer) + + verify { logger.error(match { it.contains("Failed to relay") }, any<Exception>()) } + } + + @Test + fun `relayGlobalMessage should send encoded message data`() { + val (relay, proxyServer, _) = createRelay() + val sourceServer = createRegisteredServer("lobby") + val targetServer = createRegisteredServer("survival") + + every { proxyServer.allServers } returns listOf(sourceServer, targetServer) + + relay.relayGlobalMessage(createTestMessage(), sourceServer) + + verify { + targetServer.sendPluginMessage( + any<ChannelIdentifier>(), + match<ByteArray> { it.isNotEmpty() }, + ) + } + } +} diff --git a/platform-velocity/src/test/kotlin/dev/m1sk9/lunaticChat/velocity/messaging/PluginMessageHandlerTest.kt b/platform-velocity/src/test/kotlin/dev/m1sk9/lunaticChat/velocity/messaging/PluginMessageHandlerTest.kt new file mode 100644 index 0000000..876eec6 --- /dev/null +++ b/platform-velocity/src/test/kotlin/dev/m1sk9/lunaticChat/velocity/messaging/PluginMessageHandlerTest.kt @@ -0,0 +1,211 @@ +package dev.m1sk9.lunaticChat.velocity.messaging + +import com.velocitypowered.api.event.connection.PluginMessageEvent +import com.velocitypowered.api.proxy.ProxyServer +import com.velocitypowered.api.proxy.ServerConnection +import com.velocitypowered.api.proxy.messages.ChannelIdentifier +import com.velocitypowered.api.proxy.messages.ChannelMessageSink +import com.velocitypowered.api.proxy.messages.ChannelMessageSource +import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier +import com.velocitypowered.api.proxy.server.RegisteredServer +import com.velocitypowered.api.proxy.server.ServerInfo +import dev.m1sk9.lunaticChat.engine.protocol.PluginMessage +import dev.m1sk9.lunaticChat.engine.protocol.PluginMessageCodec +import dev.m1sk9.lunaticChat.engine.protocol.ProtocolVersion +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.slf4j.Logger +import kotlin.test.Test + +class PluginMessageHandlerTest { + private val channel = MinecraftChannelIdentifier.create("lunaticchat", "main") + + private fun createHandler(pluginVersion: String = "0.10.0"): Triple<PluginMessageHandler, ProxyServer, CrossServerChatRelay> { + val plugin = Any() + val server = mockk<ProxyServer>(relaxed = true) + val logger = mockk<Logger>(relaxed = true) + val relay = mockk<CrossServerChatRelay>(relaxed = true) + + val handler = PluginMessageHandler(plugin, server, logger, pluginVersion, relay) + return Triple(handler, server, relay) + } + + private fun createServerConnection(serverName: String = "lobby"): ServerConnection { + val connection = mockk<ServerConnection>(relaxed = true) + val serverInfo = mockk<ServerInfo>(relaxed = true) + val registeredServer = mockk<RegisteredServer>(relaxed = true) + every { serverInfo.name } returns serverName + every { connection.serverInfo } returns serverInfo + every { connection.server } returns registeredServer + return connection + } + + private fun createPluginMessageEvent( + source: ChannelMessageSource, + target: ChannelMessageSink, + identifier: ChannelIdentifier, + data: ByteArray, + ): PluginMessageEvent = PluginMessageEvent(source, target, identifier, data) + + @Test + fun `onPluginMessage should handle successful handshake`() { + val (handler, _, _) = createHandler(pluginVersion = "0.10.0") + val connection = createServerConnection() + + val handshake = + PluginMessage.Handshake( + pluginVersion = "0.10.0", + protocolMajor = ProtocolVersion.MAJOR, + protocolMinor = ProtocolVersion.MINOR, + protocolPatch = ProtocolVersion.PATCH, + ) + val data = PluginMessageCodec.encode(handshake) + val event = createPluginMessageEvent(connection, mockk(relaxed = true), channel, data) + + handler.onPluginMessage(event) + + verify { connection.sendPluginMessage(any<ChannelIdentifier>(), any<ByteArray>()) } + } + + @Test + fun `onPluginMessage should reject version mismatch handshake`() { + val (handler, _, _) = createHandler(pluginVersion = "0.10.0") + val connection = createServerConnection() + + val handshake = + PluginMessage.Handshake( + pluginVersion = "0.9.0", + protocolMajor = ProtocolVersion.MAJOR, + protocolMinor = ProtocolVersion.MINOR, + protocolPatch = ProtocolVersion.PATCH, + ) + val data = PluginMessageCodec.encode(handshake) + val event = createPluginMessageEvent(connection, mockk(relaxed = true), channel, data) + + handler.onPluginMessage(event) + + verify { connection.sendPluginMessage(any<ChannelIdentifier>(), any<ByteArray>()) } + } + + @Test + fun `onPluginMessage should reject protocol mismatch handshake`() { + val (handler, _, _) = createHandler(pluginVersion = "0.10.0") + val connection = createServerConnection() + + val handshake = + PluginMessage.Handshake( + pluginVersion = "0.10.0", + protocolMajor = ProtocolVersion.MAJOR + 1, + protocolMinor = ProtocolVersion.MINOR, + protocolPatch = ProtocolVersion.PATCH, + ) + val data = PluginMessageCodec.encode(handshake) + val event = createPluginMessageEvent(connection, mockk(relaxed = true), channel, data) + + handler.onPluginMessage(event) + + verify { connection.sendPluginMessage(any<ChannelIdentifier>(), any<ByteArray>()) } + } + + @Test + fun `onPluginMessage should handle status request`() { + val (handler, _, _) = createHandler() + val connection = createServerConnection() + + val data = PluginMessageCodec.encode(PluginMessage.StatusRequest) + val event = createPluginMessageEvent(connection, mockk(relaxed = true), channel, data) + + handler.onPluginMessage(event) + + verify { connection.sendPluginMessage(any<ChannelIdentifier>(), any<ByteArray>()) } + } + + @Test + fun `onPluginMessage should relay global chat message`() { + val (handler, _, relay) = createHandler() + val connection = createServerConnection() + + val chatMessage = + PluginMessage.GlobalChatMessage( + messageId = "msg-1", + serverName = "lobby", + playerId = "00000001-0000-0000-0000-000000000000", + playerName = "TestPlayer", + message = "Hello!", + timestamp = 1000L, + ) + val data = PluginMessageCodec.encode(chatMessage) + val event = createPluginMessageEvent(connection, mockk(relaxed = true), channel, data) + + handler.onPluginMessage(event) + + verify { relay.relayGlobalMessage(any<PluginMessage.GlobalChatMessage>(), any<RegisteredServer>()) } + } + + @Test + fun `onPluginMessage should ignore messages from wrong channel`() { + val (handler, _, relay) = createHandler() + val connection = createServerConnection() + + val wrongChannel = MinecraftChannelIdentifier.create("other", "channel") + val data = PluginMessageCodec.encode(PluginMessage.StatusRequest) + val event = createPluginMessageEvent(connection, mockk(relaxed = true), wrongChannel, data) + + handler.onPluginMessage(event) + + verify(exactly = 0) { relay.relayGlobalMessage(any<PluginMessage.GlobalChatMessage>(), any<RegisteredServer>()) } + } + + @Test + fun `onPluginMessage should ignore messages from non-server source`() { + val (handler, _, relay) = createHandler() + val source = mockk<ChannelMessageSource>(relaxed = true) + + val data = PluginMessageCodec.encode(PluginMessage.StatusRequest) + val event = createPluginMessageEvent(source, mockk(relaxed = true), channel, data) + + handler.onPluginMessage(event) + + verify(exactly = 0) { relay.relayGlobalMessage(any<PluginMessage.GlobalChatMessage>(), any<RegisteredServer>()) } + } + + @Test + fun `initialize should register channel and listener`() { + val (handler, server, _) = createHandler() + + handler.initialize() + + verify { server.channelRegistrar.register(any<ChannelIdentifier>()) } + verify { server.eventManager.register(any(), handler) } + } + + @Test + fun `shutdown should unregister listener`() { + val (handler, server, _) = createHandler() + + handler.shutdown() + + verify { server.eventManager.unregisterListener(any(), handler) } + } + + @Test + fun `handshake with matching patch difference should succeed`() { + val (handler, _, _) = createHandler(pluginVersion = "0.10.0") + val connection = createServerConnection() + + val handshake = + PluginMessage.Handshake( + pluginVersion = "0.10.0", + protocolMajor = ProtocolVersion.MAJOR, + protocolMinor = ProtocolVersion.MINOR, + protocolPatch = ProtocolVersion.PATCH + 5, + ) + val data = PluginMessageCodec.encode(handshake) + val event = createPluginMessageEvent(connection, mockk(relaxed = true), channel, data) + + handler.onPluginMessage(event) + + verify { connection.sendPluginMessage(any<ChannelIdentifier>(), any<ByteArray>()) } + } +} |
