|
@@ -6,9 +6,11 @@ import com.dmdirc.ktirc.io.CaseMapping
|
6
|
6
|
import com.dmdirc.ktirc.io.LineBufferedSocket
|
7
|
7
|
import com.dmdirc.ktirc.model.*
|
8
|
8
|
import com.nhaarman.mockitokotlin2.*
|
|
9
|
+import kotlinx.coroutines.GlobalScope
|
9
|
10
|
import kotlinx.coroutines.channels.Channel
|
10
|
11
|
import kotlinx.coroutines.launch
|
11
|
12
|
import kotlinx.coroutines.runBlocking
|
|
13
|
+import kotlinx.coroutines.withTimeoutOrNull
|
12
|
14
|
import org.junit.jupiter.api.Assertions.*
|
13
|
15
|
import org.junit.jupiter.api.BeforeEach
|
14
|
16
|
import org.junit.jupiter.api.Test
|
|
@@ -44,97 +46,72 @@ internal class IrcClientImplTest {
|
44
|
46
|
|
45
|
47
|
@Test
|
46
|
48
|
fun `IrcClientImpl uses socket factory to create a new socket on connect`() {
|
47
|
|
- runBlocking {
|
48
|
|
- val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
|
49
|
|
- client.socketFactory = mockSocketFactory
|
50
|
|
- readLineChannel.close()
|
51
|
|
-
|
52
|
|
- client.connect()
|
|
49
|
+ val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
|
|
50
|
+ client.socketFactory = mockSocketFactory
|
|
51
|
+ client.connect()
|
53
|
52
|
|
54
|
|
- verify(mockSocketFactory).invoke(HOST, PORT, false)
|
55
|
|
- }
|
|
53
|
+ verify(mockSocketFactory, timeout(500)).invoke(HOST, PORT, false)
|
56
|
54
|
}
|
57
|
55
|
|
58
|
56
|
@Test
|
59
|
57
|
fun `IrcClientImpl uses socket factory to create a new tls on connect`() {
|
60
|
|
- runBlocking {
|
61
|
|
- val client = IrcClientImpl(Server(HOST, PORT, true), Profile(NICK, REAL_NAME, USER_NAME))
|
62
|
|
- client.socketFactory = mockSocketFactory
|
63
|
|
- readLineChannel.close()
|
64
|
|
-
|
65
|
|
- client.connect()
|
|
58
|
+ val client = IrcClientImpl(Server(HOST, PORT, true), Profile(NICK, REAL_NAME, USER_NAME))
|
|
59
|
+ client.socketFactory = mockSocketFactory
|
|
60
|
+ client.connect()
|
66
|
61
|
|
67
|
|
- verify(mockSocketFactory).invoke(HOST, PORT, true)
|
68
|
|
- }
|
|
62
|
+ verify(mockSocketFactory, timeout(500)).invoke(HOST, PORT, true)
|
69
|
63
|
}
|
70
|
64
|
|
71
|
65
|
@Test
|
72
|
66
|
fun `IrcClientImpl throws if socket already exists`() {
|
73
|
|
- runBlocking {
|
74
|
|
- val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
|
75
|
|
- client.socketFactory = mockSocketFactory
|
76
|
|
- readLineChannel.close()
|
|
67
|
+ val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
|
|
68
|
+ client.socketFactory = mockSocketFactory
|
|
69
|
+ client.connect()
|
77
|
70
|
|
|
71
|
+ assertThrows<IllegalStateException> {
|
78
|
72
|
client.connect()
|
79
|
|
-
|
80
|
|
- assertThrows<IllegalStateException> {
|
81
|
|
- runBlocking {
|
82
|
|
- client.connect()
|
83
|
|
- }
|
84
|
|
- }
|
85
|
73
|
}
|
86
|
74
|
}
|
87
|
75
|
|
88
|
76
|
@Test
|
89
|
|
- fun `IrcClientImpl sends basic connection strings`() {
|
90
|
|
- runBlocking {
|
91
|
|
- val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
|
92
|
|
- client.socketFactory = mockSocketFactory
|
93
|
|
- readLineChannel.close()
|
94
|
|
-
|
95
|
|
- client.connect()
|
|
77
|
+ fun `IrcClientImpl sends basic connection strings`() = runBlocking {
|
|
78
|
+ val client = IrcClientImpl(Server(HOST, PORT), Profile(NICK, REAL_NAME, USER_NAME))
|
|
79
|
+ client.socketFactory = mockSocketFactory
|
|
80
|
+ client.connect()
|
96
|
81
|
|
97
|
|
- with(inOrder(mockSocket).verify(mockSocket)) {
|
98
|
|
- sendLine("CAP LS 302")
|
99
|
|
- sendLine("NICK :$NICK")
|
100
|
|
- sendLine("USER $USER_NAME localhost $HOST :$REAL_NAME")
|
101
|
|
- }
|
|
82
|
+ with(inOrder(mockSocket).verify(mockSocket, timeout(500))) {
|
|
83
|
+ sendLine("CAP LS 302")
|
|
84
|
+ sendLine("NICK :$NICK")
|
|
85
|
+ sendLine("USER $USER_NAME localhost $HOST :$REAL_NAME")
|
102
|
86
|
}
|
103
|
87
|
}
|
104
|
88
|
|
105
|
89
|
@Test
|
106
|
|
- fun `IrcClientImpl sends password first, when present`() {
|
107
|
|
- runBlocking {
|
108
|
|
- val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
|
109
|
|
- client.socketFactory = mockSocketFactory
|
110
|
|
- readLineChannel.close()
|
111
|
|
-
|
112
|
|
- client.connect()
|
113
|
|
-
|
114
|
|
- with(inOrder(mockSocket).verify(mockSocket)) {
|
115
|
|
- sendLine("CAP LS 302")
|
116
|
|
- sendLine("PASS :$PASSWORD")
|
117
|
|
- sendLine("NICK :$NICK")
|
118
|
|
- }
|
|
90
|
+ fun `IrcClientImpl sends password first, when present`() = runBlocking {
|
|
91
|
+ val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
|
|
92
|
+ client.socketFactory = mockSocketFactory
|
|
93
|
+ client.connect()
|
|
94
|
+
|
|
95
|
+ with(inOrder(mockSocket).verify(mockSocket, timeout(500))) {
|
|
96
|
+ sendLine("CAP LS 302")
|
|
97
|
+ sendLine("PASS :$PASSWORD")
|
|
98
|
+ sendLine("NICK :$NICK")
|
119
|
99
|
}
|
120
|
100
|
}
|
121
|
101
|
|
122
|
102
|
@Test
|
123
|
103
|
fun `IrcClientImpl sends events to provided event handler`() {
|
124
|
|
- runBlocking {
|
125
|
|
- val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
|
126
|
|
- client.socketFactory = mockSocketFactory
|
127
|
|
- client.onEvent(mockEventHandler)
|
|
104
|
+ val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
|
|
105
|
+ client.socketFactory = mockSocketFactory
|
|
106
|
+ client.onEvent(mockEventHandler)
|
128
|
107
|
|
129
|
|
- launch {
|
130
|
|
- readLineChannel.send(":the.gibson 001 acidBurn :Welcome to the IRC!".toByteArray())
|
131
|
|
- readLineChannel.close()
|
132
|
|
- }
|
|
108
|
+ GlobalScope.launch {
|
|
109
|
+ readLineChannel.send(":the.gibson 001 acidBurn :Welcome to the IRC!".toByteArray())
|
|
110
|
+ }
|
133
|
111
|
|
134
|
|
- client.connect()
|
|
112
|
+ client.connect()
|
135
|
113
|
|
136
|
|
- verify(mockEventHandler).invoke(isA<ServerWelcome>())
|
137
|
|
- }
|
|
114
|
+ verify(mockEventHandler, timeout(500)).invoke(isA<ServerWelcome>())
|
138
|
115
|
}
|
139
|
116
|
|
140
|
117
|
@Test
|
|
@@ -161,4 +138,41 @@ internal class IrcClientImplTest {
|
161
|
138
|
assertFalse(client.isLocalUser(User("{acidBurn}", "libby", "root.localhost")))
|
162
|
139
|
}
|
163
|
140
|
|
|
141
|
+ @Test
|
|
142
|
+ fun `IrcClientImpl join blocks when socket is open`() {
|
|
143
|
+ val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
|
|
144
|
+ client.socketFactory = mockSocketFactory
|
|
145
|
+
|
|
146
|
+ GlobalScope.launch {
|
|
147
|
+ readLineChannel.send(":the.gibson 001 acidBurn :Welcome to the IRC!".toByteArray())
|
|
148
|
+ }
|
|
149
|
+
|
|
150
|
+ client.connect()
|
|
151
|
+ runBlocking {
|
|
152
|
+ assertNull(withTimeoutOrNull(100L) {
|
|
153
|
+ client.join()
|
|
154
|
+ true
|
|
155
|
+ })
|
|
156
|
+ }
|
|
157
|
+ }
|
|
158
|
+
|
|
159
|
+ @Test
|
|
160
|
+ fun `IrcClientImpl join returns when socket is closed`() {
|
|
161
|
+ val client = IrcClientImpl(Server(HOST, PORT, password = PASSWORD), Profile(NICK, REAL_NAME, USER_NAME))
|
|
162
|
+ client.socketFactory = mockSocketFactory
|
|
163
|
+
|
|
164
|
+ GlobalScope.launch {
|
|
165
|
+ readLineChannel.send(":the.gibson 001 acidBurn :Welcome to the IRC!".toByteArray())
|
|
166
|
+ readLineChannel.close()
|
|
167
|
+ }
|
|
168
|
+
|
|
169
|
+ client.connect()
|
|
170
|
+ runBlocking {
|
|
171
|
+ assertEquals(true, withTimeoutOrNull(500L) {
|
|
172
|
+ client.join()
|
|
173
|
+ true
|
|
174
|
+ })
|
|
175
|
+ }
|
|
176
|
+ }
|
|
177
|
+
|
164
|
178
|
}
|