Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

KtorLineBufferedSocketTest.kt 8.9KB

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