net-irc 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+