package com.shr4pnel.ferretirc import com.shr4pnel.ferretirc.net.messages.ServerMessage import io.github.oshai.kotlinlogging.KotlinLogging import kotlinx.coroutines.runBlocking import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.Test import java.io.File import java.lang.ProcessBuilder import kotlin.test.assertEquals import com.shr4pnel.ferretirc.net.messages.ClientMessage as Message class IrcClientTest { private val logger = KotlinLogging.logger {} companion object { lateinit var processes: MutableList val client = IrcClient("localhost", 6667, enableLogging = true) private val logger = KotlinLogging.logger {} val guestUser = IrcClient("localhost", 6667) @JvmStatic @BeforeAll fun setup(): Unit = runBlocking { val logFile = File("src/test/resources/logs/ngircd.log") val ngircdConfigPath = javaClass.classLoader.getResource("ngircd.conf")!!.path logFile.createNewFile() processes = ProcessBuilder.startPipeline( listOf( // Run IRC server in [-d] debug log mode, with [-n] no daemon, using config [-f] file at path ProcessBuilder("ngircd", "-dnf", ngircdConfigPath).redirectErrorStream(true), // Remove unhelpful default ngircd info [PID. relative time, GID?] ProcessBuilder("sed", "-ue", "s/\\[[^][]*\\]//g"), // Add relative timestamp ProcessBuilder("ts", "-s", "%H:%M:%.S").redirectOutput(logFile), ), ) client.connect() client.register("shr4p", "Tyler Fullname", "password") guestUser.connect() guestUser.register("guest", "guest", "pass") val default = client.server.fetchChannels().first() client.join(default) guestUser.join(default) } @JvmStatic @AfterAll fun shutdown() = runBlocking { logger.info { "Closing server." } client.queueMessage(Message.Die()) client.waitForNext() processes.forEach { it.destroy() } } } @Test fun pingGetsPong() = runBlocking { val token = "ACK" val msg = Message.Ping(token) val pong = client.queueMessageAndWaitForNext(msg) assertEquals(token, pong.token, "Token in PING did not match PONG") } @Test fun oper() = runBlocking { val mode = client.queueMessageAndWaitForNext(Message.Oper("shr4p", "password")) assertEquals("shr4p", mode.operatorName, "Received incorrect operator name in MODE") assertEquals("+o", mode.pMask, "Received unexpected mask in MODE") logger.info { "Received MODE with mask ${mode.pMask}" } } @Test fun listChannels() = runBlocking { assert( client.server.channels.value.isNotEmpty(), ) } @Test fun messageLands() = runBlocking { val channels = client.server.channels.value val message = Message.PrivMsg(channels.first(), "bring me to life") val receivedMessage = client.waitForNextMessageAfterAction { guestUser.queueMessage(message) } logger.debug { "Message: $message, Received: $receivedMessage" } assertEquals(message.message, receivedMessage.message) assertEquals(message.target.chanName, receivedMessage.targets.first()) } @Test fun manyMessagesLand() = runBlocking { val channels = client.server.channels.value val channel = channels.first() val max = 100 val messages = mutableListOf() val receivedMessages = mutableListOf() for (i in 1..max) messages.add(Message.PrivMsg(channel, "$i: bring me to life")) for (i in 0.. { guestUser.queueMessage(messages[i]) } receivedMessages.add(msg) } for (i in 0..