You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LineBufferedSocketImplTest.kt 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. package com.dmdirc.ktirc.io
  2. import kotlinx.coroutines.*
  3. import org.junit.jupiter.api.Assertions.assertEquals
  4. import org.junit.jupiter.api.Assertions.assertNotNull
  5. import org.junit.jupiter.api.Test
  6. import org.junit.jupiter.api.parallel.Execution
  7. import org.junit.jupiter.api.parallel.ExecutionMode
  8. import java.net.ServerSocket
  9. @Suppress("BlockingMethodInNonBlockingContext")
  10. @ExperimentalCoroutinesApi
  11. @Execution(ExecutionMode.SAME_THREAD)
  12. internal class LineBufferedSocketImplTest {
  13. @Test
  14. fun `can connect to a server`() = runBlocking {
  15. ServerSocket(12321).use { serverSocket ->
  16. val socket = LineBufferedSocketImpl(GlobalScope, "localhost", "localhost", 12321)
  17. val clientSocketAsync = GlobalScope.async { serverSocket.accept() }
  18. socket.connect()
  19. assertNotNull(clientSocketAsync.await())
  20. }
  21. }
  22. @Test
  23. fun `can send a byte array to a server`() = runBlocking {
  24. ServerSocket(12321).use { serverSocket ->
  25. val socket = LineBufferedSocketImpl(GlobalScope, "localhost", "localhost", 12321)
  26. val clientBytesAsync = GlobalScope.async {
  27. ByteArray(13).apply {
  28. serverSocket.accept().getInputStream().read(this)
  29. }
  30. }
  31. socket.connect()
  32. socket.sendChannel.send("Hello World".toByteArray())
  33. val bytes = clientBytesAsync.await()
  34. assertNotNull(bytes)
  35. assertEquals("Hello World\r\n", String(bytes))
  36. }
  37. }
  38. @Test
  39. fun `can send a string to a server over TLS`() = runBlocking {
  40. tlsServerSocket(12321).use { serverSocket ->
  41. val socket = LineBufferedSocketImpl(GlobalScope, "localhost", "localhost", 12321, true)
  42. socket.tlsTrustManager = getTrustingManager()
  43. val clientBytesAsync = GlobalScope.async {
  44. ByteArray(13).apply {
  45. serverSocket.accept().getInputStream().read(this)
  46. }
  47. }
  48. socket.connect()
  49. socket.sendChannel.send("Hello World".toByteArray())
  50. val bytes = clientBytesAsync.await()
  51. assertNotNull(bytes)
  52. assertEquals("Hello World\r\n", String(bytes))
  53. }
  54. }
  55. @Test
  56. fun `can receive a line of CRLF delimited text`() = runBlocking {
  57. ServerSocket(12321).use { serverSocket ->
  58. val socket = LineBufferedSocketImpl(GlobalScope, "localhost", "localhost", 12321)
  59. GlobalScope.launch {
  60. serverSocket.accept().getOutputStream().write("Hi there\r\n".toByteArray())
  61. }
  62. socket.connect()
  63. assertEquals("Hi there", String(socket.receiveChannel.receive()))
  64. }
  65. }
  66. @Test
  67. fun `can receive a line of LF delimited text`() = runBlocking {
  68. ServerSocket(12321).use { serverSocket ->
  69. val socket = LineBufferedSocketImpl(GlobalScope, "localhost", "localhost", 12321)
  70. GlobalScope.launch {
  71. serverSocket.accept().getOutputStream().write("Hi there\n".toByteArray())
  72. }
  73. socket.connect()
  74. assertEquals("Hi there", String(socket.receiveChannel.receive()))
  75. }
  76. }
  77. @Test
  78. fun `can receive multiple lines of text in one packet`() = runBlocking {
  79. ServerSocket(12321).use { serverSocket ->
  80. val socket = LineBufferedSocketImpl(GlobalScope, "localhost", "localhost", 12321)
  81. GlobalScope.launch {
  82. serverSocket.accept().getOutputStream().write("Hi there\nThis is a test\r".toByteArray())
  83. }
  84. socket.connect()
  85. val lineProducer = socket.receiveChannel
  86. assertEquals("Hi there", String(lineProducer.receive()))
  87. assertEquals("This is a test", String(lineProducer.receive()))
  88. }
  89. }
  90. @Test
  91. fun `can receive multiple long lines of text`() = runBlocking {
  92. ServerSocket(12321).use { serverSocket ->
  93. val socket = LineBufferedSocketImpl(GlobalScope, "localhost", "localhost", 12321)
  94. val line1 = "abcdefghijklmnopqrstuvwxyz".repeat(500)
  95. val line2 = "1234567890987654321[];'#,.".repeat(500)
  96. val line3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".repeat(500)
  97. GlobalScope.launch {
  98. serverSocket.accept().getOutputStream().write("$line1\r\n$line2\r$line3\n".toByteArray())
  99. }
  100. socket.connect()
  101. val lineProducer = socket.receiveChannel
  102. assertEquals(line1, String(lineProducer.receive()))
  103. assertEquals(line2, String(lineProducer.receive()))
  104. assertEquals(line3, String(lineProducer.receive()))
  105. }
  106. }
  107. @Test
  108. fun `can receive one line of text over multiple packets`() = runBlocking {
  109. ServerSocket(12321).use { serverSocket ->
  110. val socket = LineBufferedSocketImpl(GlobalScope, "localhost", "localhost", 12321)
  111. GlobalScope.launch {
  112. with(serverSocket.accept().getOutputStream()) {
  113. write("Hi".toByteArray())
  114. flush()
  115. write(" t".toByteArray())
  116. flush()
  117. write("here\r\n".toByteArray())
  118. flush()
  119. }
  120. }
  121. socket.connect()
  122. val lineProducer = socket.receiveChannel
  123. assertEquals("Hi there", String(lineProducer.receive()))
  124. }
  125. }
  126. @Test
  127. fun `returns from readLines when socket is closed`() = runBlocking {
  128. ServerSocket(12321).use { serverSocket ->
  129. val socket = LineBufferedSocketImpl(GlobalScope, "localhost", "localhost", 12321)
  130. GlobalScope.launch {
  131. with(serverSocket.accept()) {
  132. getOutputStream().write("Hi there\r\n".toByteArray())
  133. close()
  134. }
  135. }
  136. socket.connect()
  137. val lineProducer = socket.receiveChannel
  138. assertEquals("Hi there", String(lineProducer.receive()))
  139. }
  140. }
  141. @Test
  142. fun `disconnects from server`() = runBlocking {
  143. ServerSocket(12321).use { serverSocket ->
  144. val socket = LineBufferedSocketImpl(GlobalScope, "localhost", "localhost", 12321)
  145. val clientSocketAsync = GlobalScope.async { serverSocket.accept() }
  146. socket.connect()
  147. socket.disconnect()
  148. assertEquals(-1, clientSocketAsync.await().getInputStream().read()) { "Server socket should EOF after KtorLineBufferedSocket disconnects" }
  149. }
  150. }
  151. }