Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

KtorLineBufferedSocketTest.kt 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. package com.dmdirc.ktirc.io
  2. import io.ktor.network.tls.certificates.generateCertificate
  3. import kotlinx.coroutines.GlobalScope
  4. import kotlinx.coroutines.async
  5. import kotlinx.coroutines.channels.Channel
  6. import kotlinx.coroutines.launch
  7. import kotlinx.coroutines.runBlocking
  8. import org.junit.jupiter.api.Assertions.assertEquals
  9. import org.junit.jupiter.api.Assertions.assertNotNull
  10. import org.junit.jupiter.api.Test
  11. import org.junit.jupiter.api.parallel.Execution
  12. import org.junit.jupiter.api.parallel.ExecutionMode
  13. import java.io.File
  14. import java.net.ServerSocket
  15. import java.security.KeyStore
  16. import java.security.cert.X509Certificate
  17. import javax.net.ssl.KeyManagerFactory
  18. import javax.net.ssl.SSLContext
  19. import javax.net.ssl.X509TrustManager
  20. @Execution(ExecutionMode.SAME_THREAD)
  21. internal class KtorLineBufferedSocketTest {
  22. private val writeChannel = Channel<ByteArray>(Channel.UNLIMITED)
  23. @Test
  24. fun `KtorLineBufferedSocket can connect to a server`() = runBlocking {
  25. ServerSocket(12321).use { serverSocket ->
  26. val socket = KtorLineBufferedSocket("localhost", 12321)
  27. val clientSocketAsync = GlobalScope.async { serverSocket.accept() }
  28. socket.connect()
  29. assertNotNull(clientSocketAsync.await())
  30. }
  31. }
  32. @Test
  33. fun `KtorLineBufferedSocket can send a byte array to a server`() = runBlocking {
  34. ServerSocket(12321).use { serverSocket ->
  35. val socket = KtorLineBufferedSocket("localhost", 12321)
  36. val clientBytesAsync = GlobalScope.async {
  37. ByteArray(13).apply {
  38. serverSocket.accept().getInputStream().read(this)
  39. }
  40. }
  41. socket.connect()
  42. GlobalScope.launch { socket.writeLines(writeChannel) }
  43. writeChannel.send("Hello World".toByteArray())
  44. val bytes = clientBytesAsync.await()
  45. assertNotNull(bytes)
  46. assertEquals("Hello World\r\n", String(bytes))
  47. }
  48. }
  49. @Test
  50. fun `KtorLineBufferedSocket can send a string to a server over TLS`() = runBlocking {
  51. tlsServerSocket(12321).use { serverSocket ->
  52. val socket = KtorLineBufferedSocket("localhost", 12321, true)
  53. socket.tlsTrustManager = getTrustingManager()
  54. val clientBytesAsync = GlobalScope.async {
  55. ByteArray(13).apply {
  56. serverSocket.accept().getInputStream().read(this)
  57. }
  58. }
  59. socket.connect()
  60. GlobalScope.launch { socket.writeLines(writeChannel) }
  61. writeChannel.send("Hello World".toByteArray())
  62. val bytes = clientBytesAsync.await()
  63. assertNotNull(bytes)
  64. assertEquals("Hello World\r\n", String(bytes))
  65. }
  66. }
  67. @Test
  68. fun `KtorLineBufferedSocket can receive a line of CRLF delimited text`() = runBlocking {
  69. ServerSocket(12321).use { serverSocket ->
  70. val socket = KtorLineBufferedSocket("localhost", 12321)
  71. GlobalScope.launch {
  72. serverSocket.accept().getOutputStream().write("Hi there\r\n".toByteArray())
  73. }
  74. socket.connect()
  75. assertEquals("Hi there", String(socket.readLines(GlobalScope).receive()))
  76. }
  77. }
  78. @Test
  79. fun `KtorLineBufferedSocket can receive a line of LF delimited text`() = runBlocking {
  80. ServerSocket(12321).use { serverSocket ->
  81. val socket = KtorLineBufferedSocket("localhost", 12321)
  82. GlobalScope.launch {
  83. serverSocket.accept().getOutputStream().write("Hi there\n".toByteArray())
  84. }
  85. socket.connect()
  86. assertEquals("Hi there", String(socket.readLines(GlobalScope).receive()))
  87. }
  88. }
  89. @Test
  90. fun `KtorLineBufferedSocket can receive multiple lines of text in one packet`() = runBlocking {
  91. ServerSocket(12321).use { serverSocket ->
  92. val socket = KtorLineBufferedSocket("localhost", 12321)
  93. GlobalScope.launch {
  94. serverSocket.accept().getOutputStream().write("Hi there\nThis is a test\r".toByteArray())
  95. }
  96. socket.connect()
  97. val lineProducer = socket.readLines(GlobalScope)
  98. assertEquals("Hi there", String(lineProducer.receive()))
  99. assertEquals("This is a test", String(lineProducer.receive()))
  100. }
  101. }
  102. @Test
  103. fun `KtorLineBufferedSocket can receive one line of text over multiple packets`() = runBlocking {
  104. ServerSocket(12321).use { serverSocket ->
  105. val socket = KtorLineBufferedSocket("localhost", 12321)
  106. GlobalScope.launch {
  107. with(serverSocket.accept().getOutputStream()) {
  108. write("Hi".toByteArray())
  109. flush()
  110. write(" t".toByteArray())
  111. flush()
  112. write("here\r\n".toByteArray())
  113. flush()
  114. }
  115. }
  116. socket.connect()
  117. val lineProducer = socket.readLines(GlobalScope)
  118. assertEquals("Hi there", String(lineProducer.receive()))
  119. }
  120. }
  121. @Test
  122. fun `KtorLineBufferedSocket returns from readLines when socket is closed`() = runBlocking {
  123. ServerSocket(12321).use { serverSocket ->
  124. val socket = KtorLineBufferedSocket("localhost", 12321)
  125. GlobalScope.launch {
  126. with(serverSocket.accept()) {
  127. getOutputStream().write("Hi there\r\n".toByteArray())
  128. close()
  129. }
  130. }
  131. socket.connect()
  132. val lineProducer = socket.readLines(GlobalScope)
  133. assertEquals("Hi there", String(lineProducer.receive()))
  134. }
  135. }
  136. @Test
  137. fun `KtorLineBufferedSocket disconnects from server`() = runBlocking {
  138. ServerSocket(12321).use { serverSocket ->
  139. val socket = KtorLineBufferedSocket("localhost", 12321)
  140. val clientSocketAsync = GlobalScope.async { serverSocket.accept() }
  141. socket.connect()
  142. socket.disconnect()
  143. assertEquals(-1, clientSocketAsync.await().getInputStream().read()) { "Server socket should EOF after KtorLineBufferedSocket disconnects" }
  144. }
  145. }
  146. private fun tlsServerSocket(port: Int): ServerSocket {
  147. val keyFile = File.createTempFile("selfsigned", "jks")
  148. generateCertificate(keyFile)
  149. val keyStore = KeyStore.getInstance("JKS")
  150. keyStore.load(keyFile.inputStream(), "changeit".toCharArray())
  151. val keyManagerFactory = KeyManagerFactory.getInstance("PKIX")
  152. keyManagerFactory.init(keyStore, "changeit".toCharArray())
  153. val sslContext = SSLContext.getInstance("TLSv1.2")
  154. sslContext.init(keyManagerFactory.keyManagers, null, null)
  155. return sslContext.serverSocketFactory.createServerSocket(port)
  156. }
  157. private fun getTrustingManager() = object : X509TrustManager {
  158. override fun getAcceptedIssuers(): Array<X509Certificate> = emptyArray()
  159. override fun checkClientTrusted(certs: Array<X509Certificate>, authType: String) {}
  160. override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) {}
  161. }
  162. }