net-irc 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/net/irc.rb CHANGED
@@ -4,11 +4,12 @@ require "ostruct"
4
4
  require "socket"
5
5
  require "thread"
6
6
  require "logger"
7
+ require "monitor"
7
8
 
8
9
  module Net; end
9
10
 
10
11
  module Net::IRC
11
- VERSION = "0.0.1"
12
+ VERSION = "0.0.2"
12
13
  class IRCException < StandardError; end
13
14
 
14
15
  module PATTERN # :nodoc:
@@ -309,7 +310,7 @@ module Net::IRC
309
310
 
310
311
  # Extract prefix string to [nick, user, host] Array.
311
312
  def extract
312
- _, *ret = *self.match(/^([^\s!]+)!([^\s@]+)@(\S+)$/)
313
+ _, *ret = *self.match(/^([^\s!]+)(?:!([^\s@]+)@(\S+))?$/)
313
314
  ret
314
315
  end
315
316
  end
@@ -449,6 +450,7 @@ class Net::IRC::Client
449
450
  # :users => [],
450
451
  # }
451
452
  }
453
+ @channels.extend(MonitorMixin)
452
454
  end
453
455
 
454
456
  # Connect to server and start loop.
@@ -495,12 +497,12 @@ class Net::IRC::Client
495
497
  # Default RPL_WELCOME callback.
496
498
  # This sets @prefix from the message.
497
499
  def on_rpl_welcome(m)
498
- @prefix = Prefix.new(m[1][/\S+!\S+@\S+/])
500
+ @prefix = Prefix.new(m[1][/\S+$/])
499
501
  end
500
502
 
501
503
  # Default PING callback. Response PONG.
502
504
  def on_ping(m)
503
- post PONG, @nick
505
+ post PONG, @prefix ? @prefix.nick : ""
504
506
  end
505
507
 
506
508
  # For managing channel
@@ -509,29 +511,31 @@ class Net::IRC::Client
509
511
  channel = m[2]
510
512
  init_channel(channel)
511
513
 
512
- m[3].split(/\s+/).each do |u|
513
- _, mode, nick = *u.match(/^([@+]?)(.+)/)
514
+ @channels.synchronize do
515
+ m[3].split(/\s+/).each do |u|
516
+ _, mode, nick = *u.match(/^([@+]?)(.+)/)
514
517
 
515
- @channels[channel][:users] << nick
516
- @channels[channel][:users].uniq!
518
+ @channels[channel][:users] << nick
519
+ @channels[channel][:users].uniq!
517
520
 
518
- case mode
519
- when "@" # channel operator
520
- @channels[channel][:modes] << ["o", nick]
521
- when "+" # voiced (under moderating mode)
522
- @channels[channel][:modes] << ["v", nick]
521
+ case mode
522
+ when "@" # channel operator
523
+ @channels[channel][:modes] << ["o", nick]
524
+ when "+" # voiced (under moderating mode)
525
+ @channels[channel][:modes] << ["v", nick]
526
+ end
523
527
  end
524
- end
525
528
 
526
- case type
527
- when "@" # secret
528
- @channels[channel][:modes] << ["s", nil]
529
- when "*" # private
530
- @channels[channel][:modes] << ["p", nil]
531
- when "=" # public
532
- end
529
+ case type
530
+ when "@" # secret
531
+ @channels[channel][:modes] << ["s", nil]
532
+ when "*" # private
533
+ @channels[channel][:modes] << ["p", nil]
534
+ when "=" # public
535
+ end
533
536
 
534
- @channels[channel][:modes].uniq!
537
+ @channels[channel][:modes].uniq!
538
+ end
535
539
  end
536
540
 
537
541
  # For managing channel
@@ -540,12 +544,14 @@ class Net::IRC::Client
540
544
  channel = m[0]
541
545
  init_channel(channel)
542
546
 
543
- info = @channels[channel]
544
- if info
545
- info[:users].delete(nick)
546
- info[:modes].delete_if {|u|
547
- u[1] == nick
548
- }
547
+ @channels.synchronize do
548
+ info = @channels[channel]
549
+ if info
550
+ info[:users].delete(nick)
551
+ info[:modes].delete_if {|u|
552
+ u[1] == nick
553
+ }
554
+ end
549
555
  end
550
556
  end
551
557
 
@@ -553,26 +559,31 @@ class Net::IRC::Client
553
559
  def on_quit(m)
554
560
  nick = m.prefix.nick
555
561
 
556
- @channels.each do |channel, info|
557
- info[:users].delete(nick)
558
- info[:modes].delete_if {|u|
559
- u[1] == nick
560
- }
562
+ @channels.synchronize do
563
+ @channels.each do |channel, info|
564
+ info[:users].delete(nick)
565
+ info[:modes].delete_if {|u|
566
+ u[1] == nick
567
+ }
568
+ end
561
569
  end
562
570
  end
563
571
 
564
572
  # For managing channel
565
573
  def on_kick(m)
566
574
  users = m[1].split(/,/)
567
- m[0].split(/,/).each do |chan|
568
- init_channel(chan)
569
- info = @channels[chan]
570
- if info
571
- users.each do |nick|
572
- info[:users].delete(nick)
573
- info[:modes].delete_if {|u|
574
- u[1] == nick
575
- }
575
+
576
+ @channels.synchronize do
577
+ m[0].split(/,/).each do |chan|
578
+ init_channel(chan)
579
+ info = @channels[chan]
580
+ if info
581
+ users.each do |nick|
582
+ info[:users].delete(nick)
583
+ info[:modes].delete_if {|u|
584
+ u[1] == nick
585
+ }
586
+ end
576
587
  end
577
588
  end
578
589
  end
@@ -582,47 +593,52 @@ class Net::IRC::Client
582
593
  def on_join(m)
583
594
  nick = m.prefix.nick
584
595
  channel = m[0]
585
- init_channel(channel)
586
596
 
587
- @channels[channel][:users] << nick
588
- @channels[channel][:users].uniq!
597
+ @channels.synchronize do
598
+ init_channel(channel)
599
+
600
+ @channels[channel][:users] << nick
601
+ @channels[channel][:users].uniq!
602
+ end
589
603
  end
590
604
 
591
605
  # For managing channel
592
606
  def on_mode(m)
593
607
  channel = m[0]
594
- init_channel(channel)
608
+ @channels.synchronize do
609
+ init_channel(channel)
610
+
611
+ positive_mode = []
612
+ negative_mode = []
613
+
614
+ mode = positive_mode
615
+ arg_pos = 0
616
+ m[1].each_byte do |c|
617
+ case c
618
+ when ?+
619
+ mode = positive_mode
620
+ when ?-
621
+ mode = negative_mode
622
+ when ?o, ?v, ?k, ?l, ?b, ?e, ?I
623
+ mode << [c.chr, m[arg_pos + 2]]
624
+ arg_pos += 1
625
+ else
626
+ mode << [c.chr, nil]
627
+ end
628
+ end
629
+ mode = nil
595
630
 
596
- positive_mode = []
597
- negative_mode = []
598
-
599
- mode = positive_mode
600
- arg_pos = 0
601
- m[1].each_byte do |c|
602
- case c
603
- when ?+
604
- mode = positive_mode
605
- when ?-
606
- mode = negative_mode
607
- when ?o, ?v, ?k, ?l, ?b, ?e, ?I
608
- mode << [c.chr, m[arg_pos + 2]]
609
- arg_pos += 1
610
- else
611
- mode << [c.chr, nil]
631
+ negative_mode.each do |m|
632
+ @channels[channel][:modes].delete(m)
612
633
  end
613
- end
614
- mode = nil
615
634
 
616
- negative_mode.each do |m|
617
- @channels[channel][:modes].delete(m)
618
- end
635
+ positive_mode.each do |m|
636
+ @channels[channel][:modes] << m
637
+ end
619
638
 
620
- positive_mode.each do |m|
621
- @channels[channel][:modes] << m
639
+ @channels[channel][:modes].uniq!
640
+ [negative_mode, positive_mode]
622
641
  end
623
-
624
- @channels[channel][:modes].uniq!
625
- [negative_mode, positive_mode]
626
642
  end
627
643
 
628
644
  # For managing channel
@@ -719,7 +735,7 @@ class Net::IRC::Server
719
735
 
720
736
  # Override subclass.
721
737
  def server_name
722
- "Net::IRC::Server::Session"
738
+ "net-irc"
723
739
  end
724
740
 
725
741
  # Override subclass.
@@ -830,15 +846,17 @@ class Net::IRC::Server
830
846
  })
831
847
  @log.debug "SEND: #{m.to_s.chomp}"
832
848
  @socket << m
849
+ rescue IOError
850
+ finish
833
851
  end
834
852
 
835
853
  # Call when client connected.
836
854
  # Send RPL_WELCOME sequence. If you want to customize, override this method at subclass.
837
855
  def inital_message
838
- post nil, RPL_WELCOME, @nick, "Welcome to the Internet Relay Network #{@prefix}"
839
- post nil, RPL_YOURHOST, @nick, "Your host is #{server_name}, running version #{server_version}"
840
- post nil, RPL_CREATED, @nick, "This server was created #{Time.now}"
841
- post nil, RPL_MYINFO, @nick, "#{server_name} #{server_version} #{avaiable_user_modes} #{avaiable_channel_modes}"
856
+ post server_name, RPL_WELCOME, @nick, "Welcome to the Internet Relay Network #{@prefix}"
857
+ post server_name, RPL_YOURHOST, @nick, "Your host is #{server_name}, running version #{server_version}"
858
+ post server_name, RPL_CREATED, @nick, "This server was created #{Time.now}"
859
+ post server_name, RPL_MYINFO, @nick, "#{server_name} #{server_version} #{avaiable_user_modes} #{avaiable_channel_modes}"
842
860
  end
843
861
  end
844
862
  end # Server
@@ -0,0 +1,385 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH << "lib"
4
+ $LOAD_PATH << "../lib"
5
+
6
+ require "net/irc"
7
+ include Net::IRC
8
+ include Constants
9
+
10
+ describe Net::IRC::Message, "construct" do
11
+
12
+ it "should generate message correctly" do
13
+ m = Message.new("foo", "PRIVMSG", ["#channel", "message"])
14
+ m.to_s.should == ":foo PRIVMSG #channel message\r\n"
15
+
16
+ m = Message.new("foo", "PRIVMSG", ["#channel", "message with space"])
17
+ m.to_s.should == ":foo PRIVMSG #channel :message with space\r\n"
18
+
19
+ m = Message.new(nil, "PRIVMSG", ["#channel", "message"])
20
+ m.to_s.should == "PRIVMSG #channel message\r\n"
21
+
22
+ m = Message.new(nil, "PRIVMSG", ["#channel", "message with space"])
23
+ m.to_s.should == "PRIVMSG #channel :message with space\r\n"
24
+
25
+ m = Message.new(nil, "MODE", [
26
+ "#channel",
27
+ "+ooo",
28
+ "nick1",
29
+ "nick2",
30
+ "nick3"
31
+ ])
32
+ m.to_s.should == "MODE #channel +ooo nick1 nick2 nick3\r\n"
33
+
34
+ m = Message.new(nil, "KICK", [
35
+ "#channel,#channel1",
36
+ "nick1,nick2",
37
+ ])
38
+ m.to_s.should == "KICK #channel,#channel1 nick1,nick2\r\n"
39
+ end
40
+
41
+ it "should have ctcp? method" do
42
+ m = Message.new("foo", "PRIVMSG", ["#channel", "\x01ACTION foo\x01"])
43
+ m.ctcp?.should be_true
44
+ end
45
+
46
+ it "should behave as Array contains params" do
47
+ m = Message.new("foo", "PRIVMSG", ["#channel", "message"])
48
+ m[0].should == m.params[0]
49
+ m[1].should == m.params[1]
50
+ m.to_a.should == ["#channel", "message"]
51
+
52
+ channel, message = *m
53
+ channel.should == "#channel"
54
+ message.should == "message"
55
+ end
56
+ end
57
+
58
+ describe Net::IRC::Message, "parse" do
59
+ it "should parse correctly following RFC." do
60
+ m = Message.parse("PRIVMSG #channel message\r\n")
61
+ m.prefix.should == ""
62
+ m.command.should == "PRIVMSG"
63
+ m.params.should == ["#channel", "message"]
64
+
65
+ m = Message.parse("PRIVMSG #channel :message leading :\r\n")
66
+ m.prefix.should == ""
67
+ m.command.should == "PRIVMSG"
68
+ m.params.should == ["#channel", "message leading :"]
69
+
70
+ m = Message.parse("PRIVMSG #channel middle :message leading :\r\n")
71
+ m.prefix.should == ""
72
+ m.command.should == "PRIVMSG"
73
+ m.params.should == ["#channel", "middle", "message leading :"]
74
+
75
+ m = Message.parse("PRIVMSG #channel middle message with middle\r\n")
76
+ m.prefix.should == ""
77
+ m.command.should == "PRIVMSG"
78
+ m.params.should == ["#channel", "middle", "message", "with", "middle"]
79
+
80
+ m = Message.parse(":prefix PRIVMSG #channel message\r\n")
81
+ m.prefix.should == "prefix"
82
+ m.command.should == "PRIVMSG"
83
+ m.params.should == ["#channel", "message"]
84
+
85
+ m = Message.parse(":prefix PRIVMSG #channel :message leading :\r\n")
86
+ m.prefix.should == "prefix"
87
+ m.command.should == "PRIVMSG"
88
+ m.params.should == ["#channel", "message leading :"]
89
+ end
90
+
91
+ it "should allow multibyte " do
92
+ m = Message.parse(":てすと PRIVMSG #channel :message leading :\r\n")
93
+ m.prefix.should == "てすと"
94
+ m.command.should == "PRIVMSG"
95
+ m.params.should == ["#channel", "message leading :"]
96
+ end
97
+
98
+ it "should allow space at end" do
99
+ m = Message.parse("JOIN #foobar \r\n")
100
+ m.prefix.should == ""
101
+ m.command.should == "JOIN"
102
+ m.params.should == ["#foobar"]
103
+ end
104
+ end
105
+
106
+ describe Net::IRC::Constants, "lookup" do
107
+ it "should lookup numeric replies from Net::IRC::COMMANDS" do
108
+ welcome = Net::IRC::Constants.const_get("RPL_WELCOME")
109
+ welcome.should == "001"
110
+ Net::IRC::COMMANDS[welcome].should == "RPL_WELCOME"
111
+ end
112
+ end
113
+
114
+ describe Net::IRC::Prefix, "" do
115
+ it "should be kind of String" do
116
+ Prefix.new("").should be_kind_of(String)
117
+ end
118
+
119
+ it "should parse prefix correctly." do
120
+ prefix = Prefix.new("foo!bar@localhost")
121
+ prefix.extract.should == ["foo", "bar", "localhost"]
122
+
123
+ prefix = Prefix.new("foo!-bar@localhost")
124
+ prefix.extract.should == ["foo", "-bar", "localhost"]
125
+
126
+ prefix = Prefix.new("foo!+bar@localhost")
127
+ prefix.extract.should == ["foo", "+bar", "localhost"]
128
+
129
+ prefix = Prefix.new("foo!~bar@localhost")
130
+ prefix.extract.should == ["foo", "~bar", "localhost"]
131
+ end
132
+
133
+ it "should allow multibyte in nick." do
134
+ prefix = Prefix.new("あああ!~bar@localhost")
135
+ prefix.extract.should == ["あああ", "~bar", "localhost"]
136
+ end
137
+
138
+ it "should allow lame prefix." do
139
+ prefix = Prefix.new("nick")
140
+ prefix.extract.should == ["nick", nil, nil]
141
+ end
142
+
143
+ it "has nick method" do
144
+ prefix = Prefix.new("foo!bar@localhost")
145
+ prefix.nick.should == "foo"
146
+ end
147
+
148
+ it "has user method" do
149
+ prefix = Prefix.new("foo!bar@localhost")
150
+ prefix.user.should == "bar"
151
+ end
152
+
153
+ it "has host method" do
154
+ prefix = Prefix.new("foo!bar@localhost")
155
+ prefix.host.should == "localhost"
156
+ end
157
+ end
158
+
159
+ describe Net::IRC, "utilities" do
160
+ it "has ctcp_encoding method" do
161
+ message = ctcp_encoding "ACTION hehe"
162
+ message.should == "\x01ACTION hehe\x01"
163
+
164
+ message = ctcp_encoding "ACTION \x01 \x5c "
165
+ message.should == "\x01ACTION \x5c\x61 \x5c\x5c \x01"
166
+
167
+ message = ctcp_encoding "ACTION \x00 \x0a \x0d \x10 "
168
+ message.should == "\x01ACTION \x100 \x10n \x10r \x10\x10 \x01"
169
+ end
170
+
171
+ it "has ctcp_decoding method" do
172
+ message = ctcp_decoding "\x01ACTION hehe\x01"
173
+ message.should == "ACTION hehe"
174
+
175
+ message = ctcp_decoding "\x01ACTION \x5c\x61 \x5c\x5c \x01"
176
+ message.should == "ACTION \x01 \x5c "
177
+
178
+ message = ctcp_decoding "\x01ACTION \x100 \x10n \x10r \x10\x10 \x01"
179
+ message.should == "ACTION \x00 \x0a \x0d \x10 "
180
+ end
181
+ end
182
+
183
+ class TestServerSession < Net::IRC::Server::Session
184
+ @@testq = SizedQueue.new(1)
185
+ @@instance = nil
186
+
187
+ def self.testq
188
+ @@testq
189
+ end
190
+
191
+ def self.instance
192
+ @@instance
193
+ end
194
+
195
+ def initialize(*args)
196
+ super
197
+ @@instance = self
198
+ end
199
+
200
+ def on_message(m)
201
+ @@testq << m
202
+ end
203
+ end
204
+
205
+ class TestClient < Net::IRC::Client
206
+ @@testq = SizedQueue.new(1)
207
+
208
+ def self.testq
209
+ @@testq
210
+ end
211
+
212
+ def on_message(m)
213
+ @@testq << m
214
+ end
215
+ end
216
+
217
+ describe Net::IRC, "server and client" do
218
+ before :all do
219
+ @port = nil
220
+ @server, @client = nil, nil
221
+
222
+ Thread.abort_on_exception = true
223
+ Thread.start do
224
+ @server = Net::IRC::Server.new("localhost", @port, TestServerSession, {
225
+ :logger => Logger.new(nil),
226
+ })
227
+ @server.start
228
+ end
229
+
230
+ true until @server.instance_variable_get(:@serv)
231
+
232
+ @port = @server.instance_variable_get(:@serv).addr[1]
233
+
234
+ Thread.start do
235
+ @client = TestClient.new("localhost", @port, {
236
+ :nick => "foonick",
237
+ :user => "foouser",
238
+ :real => "foo real name",
239
+ :pass => "foopass",
240
+ :logger => Logger.new(nil),
241
+ })
242
+ @client.start
243
+ end
244
+ end
245
+
246
+ server_q = TestServerSession.testq
247
+ client_q = TestClient.testq
248
+
249
+ it "client should send pass/nick/user sequence." do
250
+ server_q.pop.to_s.should == "PASS foopass\r\n"
251
+ server_q.pop.to_s.should == "NICK foonick\r\n"
252
+ server_q.pop.to_s.should == "USER foouser 0 * :foo real name\r\n"
253
+ end
254
+
255
+ it "server should send 001,002,003 numeric replies." do
256
+ client_q.pop.to_s.should match(/^:net-irc 001 foonick :Welcome to the Internet Relay Network \S+!\S+@\S+/)
257
+ client_q.pop.to_s.should match(/^:net-irc 002 foonick :Your host is .+?, running version /)
258
+ client_q.pop.to_s.should match(/^:net-irc 003 foonick :This server was created /)
259
+ end
260
+
261
+ it "client posts PRIVMSG and server receives it." do
262
+ @client.instance_eval do
263
+ post PRIVMSG, "#channel", "message a b c"
264
+ end
265
+
266
+ message = server_q.pop
267
+ message.should be_a_kind_of(Net::IRC::Message)
268
+ message.to_s.should == "PRIVMSG #channel :message a b c\r\n"
269
+ end
270
+
271
+ it "client should manage channel mode/users correctly" do
272
+ client = @client
273
+ c = @client.instance_variable_get(:@channels)
274
+ TestServerSession.instance.instance_eval do
275
+ Thread.exclusive do
276
+ post client.prefix, JOIN, "#test"
277
+ post nil, NOTICE, "#test", "sep1"
278
+ end
279
+ end
280
+
281
+ true until client_q.pop.to_s == "NOTICE #test sep1\r\n"
282
+ c.synchronize do
283
+ c.should be_a_kind_of(Hash)
284
+ c["#test"].should be_a_kind_of(Hash)
285
+ c["#test"][:modes].should be_a_kind_of(Array)
286
+ c["#test"][:users].should be_a_kind_of(Array)
287
+ c["#test"][:users].should == ["foonick"]
288
+ end
289
+
290
+ TestServerSession.instance.instance_eval do
291
+ Thread.exclusive do
292
+ post "test1!test@localhost", JOIN, "#test"
293
+ post "test2!test@localhost", JOIN, "#test"
294
+ post nil, NOTICE, "#test", "sep2"
295
+ end
296
+ end
297
+
298
+ true until client_q.pop.to_s == "NOTICE #test sep2\r\n"
299
+ c.synchronize do
300
+ c["#test"][:users].should == ["foonick", "test1", "test2"]
301
+ end
302
+
303
+ TestServerSession.instance.instance_eval do
304
+ Thread.exclusive do
305
+ post nil, RPL_NAMREPLY, client.prefix.nick, "@", "#test", "foo1 foo2 foo3 @foo4 +foo5"
306
+ post nil, NOTICE, "#test", "sep3"
307
+ end
308
+ end
309
+
310
+ true until client_q.pop.to_s == "NOTICE #test sep3\r\n"
311
+ c.synchronize do
312
+ c["#test"][:users].should == ["foonick", "test1", "test2", "foo1", "foo2", "foo3", "foo4", "foo5"]
313
+ c["#test"][:modes].should include(["s", nil])
314
+ c["#test"][:modes].should include(["o", "foo4"])
315
+ c["#test"][:modes].should include(["v", "foo5"])
316
+ end
317
+
318
+ TestServerSession.instance.instance_eval do
319
+ Thread.exclusive do
320
+ post nil, RPL_NAMREPLY, client.prefix.nick, "@", "#test1", "foo1 foo2 foo3 @foo4 +foo5"
321
+ post "foo4!foo@localhost", QUIT, "message"
322
+ post "foo5!foo@localhost", PART, "#test1", "message"
323
+ post client.prefix, KICK, "#test", "foo1", "message"
324
+ post client.prefix, MODE, "#test", "+o", "foo2"
325
+ post nil, NOTICE, "#test", "sep4"
326
+ end
327
+ end
328
+
329
+ true until client_q.pop.to_s == "NOTICE #test sep4\r\n"
330
+ c.synchronize do
331
+ c["#test"][:users].should == ["foonick", "test1", "test2", "foo2", "foo3", "foo5"]
332
+ c["#test1"][:users].should == ["foo1", "foo2", "foo3"]
333
+ c["#test"][:modes].should_not include(["o", "foo4"])
334
+ c["#test"][:modes].should include(["v", "foo5"])
335
+ c["#test1"][:modes].should_not include(["v", "foo5"])
336
+ c["#test"][:modes].should include(["o", "foo2"])
337
+ end
338
+ end
339
+
340
+ it "should allow lame RPL_WELCOME (not prefix but nick)" do
341
+ client = @client
342
+ TestServerSession.instance.instance_eval do
343
+ Thread.exclusive do
344
+ post "server", RPL_WELCOME, client.prefix.nick, "Welcome to the Internet Relay Network #{client.prefix.nick}"
345
+ post nil, NOTICE, "#test", "sep1"
346
+ end
347
+ end
348
+ true until client_q.pop.to_s == "NOTICE #test sep1\r\n"
349
+ client.prefix.should == "foonick"
350
+ end
351
+
352
+ it "should destroy closed session" do
353
+ oldclient = @client
354
+ @client.finish
355
+
356
+ Thread.start do
357
+ @client = TestClient.new("localhost", @port, {
358
+ :nick => "foonick",
359
+ :user => "foouser",
360
+ :real => "foo real name",
361
+ :pass => "foopass",
362
+ :logger => Logger.new(nil),
363
+ })
364
+ @client.start
365
+ end
366
+
367
+ Thread.pass
368
+ true while @client == oldclient
369
+
370
+ c = @client.instance_variable_get(:@channels)
371
+ TestServerSession.instance.instance_eval do
372
+ Thread.exclusive do
373
+ post nil, NOTICE, "#test", "sep1"
374
+ end
375
+ end
376
+
377
+ true until client_q.pop.to_s == "NOTICE #test sep1\r\n"
378
+ end
379
+
380
+ after :all do
381
+ @server.finish
382
+ @client.finish
383
+ end
384
+ end
385
+