calidion
02/17/2025, 10:43 AMclass UDPServer(val port: Int) {
private val clients = ConcurrentHashMap<String, NatClientInfo>()
private val socket = DatagramSocket(port)
fun start() {
Thread {
println("UDP Server started on port $port")
while (true) {
val buffer = ByteArray(UDP_BUFFER_SIZE)
val packet = DatagramPacket(buffer, buffer.size)
socket.receive(packet)
val message = String(packet.data, 0, packet.length)
val senderIp = packet.address.hostAddress
val senderPort = packet.port
handleMessage(message, senderIp, senderPort)
}
}.start()
}
fun handleMessage(message: String, senderIp: String, senderPort: Int) {
println("Received UDP from $senderIp:$senderPort -> $message")
val parts = message.split(" ")
if (parts.size >= 2 && parts[0] == MSG_REGISTER) {
val address = parts[1]
clients[address]?.apply {
publicIp = senderIp
publicPort = senderPort
}
println("Registered UDP Client: $address -> $senderIp:$senderPort")
} else if (parts.size >= 2 && parts[0] == MSG_REQUEST_PEER) {
val targetAddress = parts[1]
val target = clients[targetAddress]
if (target?.publicIp != null && target.publicPort != null) {
val response = "$MSG_PEER_RESPONSE ${target.publicIp} ${target.publicPort}"
sendMessage(senderIp, senderPort, response)
} else {
sendMessage(senderIp, senderPort, MSG_PEER_NOT_FOUND)
}
}
}
private fun sendMessage(ip: String, port: Int, message: String) {
val buffer = message.toByteArray()
val packet = DatagramPacket(buffer, buffer.size, InetAddress.getByName(ip), port)
socket.send(packet)
}
}
Arne Jans
02/18/2025, 3:29 PMUDPServer
in a setup-method in a JUnit-Test file and in the test-methods just instantiate a client, communicate with the server-instance and check relevant results.
If you want to unit-test the single server-methods in isolation, I would first consider refactoring the code to dependency-inject the network-specific stuff like the clients-registry and the socket via the UDPServer
-constructor and mock them in the test, e.g. with mockk
. Then you can mock their behavior and check their usage.
You might also want to split the code in handleMessage
-method into two additional handle-methods to be able to test them clearly separated from another (since it seems to me the code handles 2 separate use-cases, ie message-types).