Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

IrcClientTest.kt 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. package com.dmdirc.ktirc
  2. import com.dmdirc.ktirc.events.IrcEvent
  3. import com.dmdirc.ktirc.events.ServerWelcome
  4. import com.dmdirc.ktirc.io.CaseMapping
  5. import com.dmdirc.ktirc.io.LineBufferedSocket
  6. import com.dmdirc.ktirc.model.*
  7. import com.nhaarman.mockitokotlin2.*
  8. import kotlinx.coroutines.GlobalScope
  9. import kotlinx.coroutines.channels.Channel
  10. import kotlinx.coroutines.launch
  11. import kotlinx.coroutines.runBlocking
  12. import kotlinx.coroutines.withTimeoutOrNull
  13. import org.junit.jupiter.api.Assertions.*
  14. import org.junit.jupiter.api.BeforeEach
  15. import org.junit.jupiter.api.Test
  16. import org.junit.jupiter.api.assertThrows
  17. internal class IrcClientImplTest {
  18. companion object {
  19. private const val HOST = "thegibson.com"
  20. private const val PORT = 12345
  21. private const val NICK = "AcidBurn"
  22. private const val REAL_NAME = "Kate Libby"
  23. private const val USER_NAME = "acidb"
  24. private const val PASSWORD = "HackThePlanet"
  25. }
  26. private val readLineChannel = Channel<ByteArray>(10)
  27. private val mockSocket = mock<LineBufferedSocket> {
  28. on { readLines(any()) } doReturn readLineChannel
  29. }
  30. private val mockSocketFactory = mock<(String, Int, Boolean) -> LineBufferedSocket> {
  31. on { invoke(eq(HOST), eq(PORT), any()) } doReturn mockSocket
  32. }
  33. private val mockEventHandler = mock<(IrcEvent) -> Unit>()
  34. @BeforeEach
  35. fun setUp() {
  36. IrcMessage.currentTimeProvider = { TestConstants.time }
  37. }
  38. @Test
  39. fun `IrcClientImpl uses socket factory to create a new socket on connect`() {
  40. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  41. client.socketFactory = mockSocketFactory
  42. client.connect()
  43. verify(mockSocketFactory, timeout(500)).invoke(HOST, PORT, false)
  44. }
  45. @Test
  46. fun `IrcClientImpl uses socket factory to create a new tls on connect`() {
  47. val client = IrcClientImpl(Server(HOST, PORT, true), Profile(NICK, REAL_NAME, USER_NAME))
  48. client.socketFactory = mockSocketFactory
  49. client.connect()
  50. verify(mockSocketFactory, timeout(500)).invoke(HOST, PORT, true)
  51. }
  52. @Test
  53. fun `IrcClientImpl throws if socket already exists`() {
  54. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  55. client.socketFactory = mockSocketFactory
  56. client.connect()
  57. assertThrows<IllegalStateException> {
  58. client.connect()
  59. }
  60. }
  61. @Test
  62. fun `IrcClientImpl sends basic connection strings`() = runBlocking {
  63. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  64. client.socketFactory = mockSocketFactory
  65. client.connect()
  66. with(inOrder(mockSocket).verify(mockSocket, timeout(500))) {
  67. sendLine("CAP LS 302")
  68. sendLine("NICK :$NICK")
  69. sendLine("USER $USER_NAME localhost $HOST :$REAL_NAME")
  70. }
  71. }
  72. @Test
  73. fun `IrcClientImpl sends password first, when present`() = runBlocking {
  74. val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
  75. client.socketFactory = mockSocketFactory
  76. client.connect()
  77. with(inOrder(mockSocket).verify(mockSocket, timeout(500))) {
  78. sendLine("CAP LS 302")
  79. sendLine("PASS :$PASSWORD")
  80. sendLine("NICK :$NICK")
  81. }
  82. }
  83. @Test
  84. fun `IrcClientImpl sends events to provided event handler`() {
  85. val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
  86. client.socketFactory = mockSocketFactory
  87. client.onEvent(mockEventHandler)
  88. GlobalScope.launch {
  89. readLineChannel.send(":the.gibson 001 acidBurn :Welcome to the IRC!".toByteArray())
  90. }
  91. client.connect()
  92. verify(mockEventHandler, timeout(500)).invoke(isA<ServerWelcome>())
  93. }
  94. @Test
  95. fun `IrcClient gets case mapping from server features`() {
  96. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  97. client.serverState.features[ServerFeature.ServerCaseMapping] = CaseMapping.RfcStrict
  98. assertEquals(CaseMapping.RfcStrict, client.caseMapping)
  99. }
  100. @Test
  101. fun `IrcClient indicates if user is local user or not`() {
  102. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  103. client.serverState.localNickname = "[acidBurn]"
  104. assertTrue(client.isLocalUser(User("{acidBurn}", "libby", "root.localhost")))
  105. assertFalse(client.isLocalUser(User("acid-Burn", "libby", "root.localhost")))
  106. }
  107. @Test
  108. fun `IrcClient uses current case mapping to check local user`() {
  109. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  110. client.serverState.localNickname = "[acidBurn]"
  111. client.serverState.features[ServerFeature.ServerCaseMapping] = CaseMapping.Ascii
  112. assertFalse(client.isLocalUser(User("{acidBurn}", "libby", "root.localhost")))
  113. }
  114. @Test
  115. fun `IrcClientImpl join blocks when socket is open`() {
  116. val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
  117. client.socketFactory = mockSocketFactory
  118. GlobalScope.launch {
  119. readLineChannel.send(":the.gibson 001 acidBurn :Welcome to the IRC!".toByteArray())
  120. }
  121. client.connect()
  122. runBlocking {
  123. assertNull(withTimeoutOrNull(100L) {
  124. client.join()
  125. true
  126. })
  127. }
  128. }
  129. @Test
  130. fun `IrcClientImpl join returns when socket is closed`() {
  131. val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
  132. client.socketFactory = mockSocketFactory
  133. GlobalScope.launch {
  134. readLineChannel.send(":the.gibson 001 acidBurn :Welcome to the IRC!".toByteArray())
  135. readLineChannel.close()
  136. }
  137. client.connect()
  138. runBlocking {
  139. assertEquals(true, withTimeoutOrNull(500L) {
  140. client.join()
  141. true
  142. })
  143. }
  144. }
  145. @Test
  146. fun `IrcClientImpl sends text to socket`() = runBlocking {
  147. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  148. client.socketFactory = mockSocketFactory
  149. client.connect()
  150. // Wait for it to connect
  151. verify(mockSocket, timeout(500)).sendLine("CAP LS 302")
  152. client.send("testing 123")
  153. verify(mockSocket, timeout(500)).sendLine("testing 123")
  154. }
  155. @Test
  156. fun `IrcClientImpl disconnects the socket`() = runBlocking {
  157. val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
  158. client.socketFactory = mockSocketFactory
  159. client.connect()
  160. // Wait for it to connect
  161. verify(mockSocket, timeout(500)).sendLine("CAP LS 302")
  162. client.disconnect()
  163. verify(mockSocket, timeout(500)).disconnect()
  164. }
  165. }