eventmachine 0.8.0 → 0.8.1
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/README +9 -5
- data/ext/autoscan.log +0 -0
- data/ext/cmain.cpp +76 -1
- data/ext/cplusplus.cpp +175 -0
- data/ext/ed.cpp +27 -2
- data/ext/ed.h +4 -1
- data/ext/eventmachine.h +3 -1
- data/ext/eventmachine_cpp.h +94 -0
- data/ext/extconf.rb +7 -1
- data/ext/project.h +9 -3
- data/ext/rubymain.cpp +44 -1
- data/lib/em/deferrable.rb +30 -5
- data/lib/em/streamer.rb +114 -0
- data/lib/eventmachine.rb +50 -2
- data/lib/eventmachine_version.rb +2 -2
- data/lib/jeventmachine.rb +106 -0
- data/lib/protocols/linetext2.rb +145 -0
- data/lib/protocols/stomp.rb +127 -0
- data/tests/test_basic.rb +10 -8
- data/tests/test_epoll.rb +8 -5
- data/tests/test_ltp.rb +7 -1
- data/tests/test_ltp2.rb +260 -0
- data/tests/test_send_file.rb +236 -0
- data/tests/test_servers.rb +87 -0
- metadata +12 -2
@@ -0,0 +1,145 @@
|
|
1
|
+
# $Id: linetext2.rb 486 2007-07-29 17:15:12Z blackhedd $
|
2
|
+
#
|
3
|
+
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
|
+
# Homepage:: http://rubyeventmachine.com
|
5
|
+
# Date:: 15 November 2006
|
6
|
+
#
|
7
|
+
# See EventMachine and EventMachine::Connection for documentation and
|
8
|
+
# usage examples.
|
9
|
+
#
|
10
|
+
#----------------------------------------------------------------------------
|
11
|
+
#
|
12
|
+
# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
13
|
+
# Gmail: blackhedd
|
14
|
+
#
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
16
|
+
# it under the terms of either: 1) the GNU General Public License
|
17
|
+
# as published by the Free Software Foundation; either version 2 of the
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
+
#
|
20
|
+
# See the file COPYING for complete licensing information.
|
21
|
+
#
|
22
|
+
#---------------------------------------------------------------------------
|
23
|
+
#
|
24
|
+
#
|
25
|
+
#
|
26
|
+
|
27
|
+
|
28
|
+
# In the grand, time-honored tradition of re-inventing the wheel, we offer
|
29
|
+
# here YET ANOTHER protocol that handles line-oriented data with interspersed
|
30
|
+
# binary text. This one trades away some of the performance optimizations of
|
31
|
+
# EventMachine::Protocols::LineAndTextProtocol in order to get better correctness
|
32
|
+
# with regard to binary text blocks that can switch back to line mode. It also
|
33
|
+
# permits the line-delimiter to change in midstream.
|
34
|
+
# This was originally written to support Stomp.
|
35
|
+
|
36
|
+
# TODO! We're not enforcing the limits on header lengths and text-lengths.
|
37
|
+
# When we get around to that, call #receive_error if the user defined it, otherwise
|
38
|
+
# throw exceptions.
|
39
|
+
|
40
|
+
module EventMachine
|
41
|
+
module Protocols
|
42
|
+
module LineText2
|
43
|
+
MaxLineLength = 16*1024
|
44
|
+
MaxBinaryLength = 32*1024*1024
|
45
|
+
|
46
|
+
#--
|
47
|
+
# Will be called recursively until there's no data to read.
|
48
|
+
# That way the user-defined handlers we call can modify the
|
49
|
+
# handling characteristics on a per-token basis.
|
50
|
+
#
|
51
|
+
def receive_data data
|
52
|
+
return unless (data and data.length > 0)
|
53
|
+
|
54
|
+
# Do this stuff in lieu of a constructor.
|
55
|
+
@lt2_mode ||= :lines
|
56
|
+
@lt2_delimiter ||= "\n"
|
57
|
+
@lt2_linebuffer ||= []
|
58
|
+
|
59
|
+
if @lt2_mode == :lines
|
60
|
+
if ix = data.index( @lt2_delimiter )
|
61
|
+
@lt2_linebuffer << data[0...ix]
|
62
|
+
ln = @lt2_linebuffer.join
|
63
|
+
@lt2_linebuffer.clear
|
64
|
+
if @lt2_delimiter == "\n"
|
65
|
+
ln.chomp!
|
66
|
+
end
|
67
|
+
receive_line ln
|
68
|
+
receive_data data[(ix+@lt2_delimiter.length)..-1]
|
69
|
+
else
|
70
|
+
@lt2_linebuffer << data
|
71
|
+
end
|
72
|
+
elsif @lt2_mode == :text
|
73
|
+
if @lt2_textsize
|
74
|
+
needed = @lt2_textsize - @lt2_textpos
|
75
|
+
will_take = if data.length > needed
|
76
|
+
needed
|
77
|
+
else
|
78
|
+
data.length
|
79
|
+
end
|
80
|
+
|
81
|
+
@lt2_textbuffer << data[0...will_take]
|
82
|
+
tail = data[will_take..-1]
|
83
|
+
|
84
|
+
@lt2_textpos += will_take
|
85
|
+
if @lt2_textpos >= @lt2_textsize
|
86
|
+
receive_binary_data @lt2_textbuffer.join
|
87
|
+
set_line_mode
|
88
|
+
end
|
89
|
+
|
90
|
+
receive_data tail
|
91
|
+
else
|
92
|
+
receive_binary_data data
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
def set_delimiter delim
|
99
|
+
@lt2_delimiter = delim.to_s
|
100
|
+
end
|
101
|
+
|
102
|
+
# Called internally but also exposed to user code, for the case in which
|
103
|
+
# processing of binary data creates a need to transition back to line mode.
|
104
|
+
# We support an optional parameter to "throw back" some data, which might
|
105
|
+
# be an umprocessed chunk of the transmitted binary data, or something else
|
106
|
+
# entirely.
|
107
|
+
def set_line_mode data=""
|
108
|
+
@lt2_mode = :lines
|
109
|
+
(@lt2_linebuffer ||= []).clear
|
110
|
+
receive_data data.to_s
|
111
|
+
end
|
112
|
+
|
113
|
+
def set_text_mode size=nil
|
114
|
+
if size == 0
|
115
|
+
set_line_mode
|
116
|
+
else
|
117
|
+
@lt2_mode = :text
|
118
|
+
(@lt2_textbuffer ||= []).clear
|
119
|
+
@lt2_textsize = size # which can be nil, signifying no limit
|
120
|
+
@lt2_textpos = 0
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# In case of a dropped connection, we'll send a partial buffer to user code
|
125
|
+
# when in sized text mode. User overrides of #receive_binary_data need to
|
126
|
+
# be aware that they may get a short buffer.
|
127
|
+
def unbind
|
128
|
+
if @lt2_mode == :text and @lt2_textpos > 0
|
129
|
+
receive_binary_data @lt2_textbuffer.join
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Stub. Should be subclassed by user code.
|
134
|
+
def receive_line ln
|
135
|
+
# no-op
|
136
|
+
end
|
137
|
+
|
138
|
+
# Stub. Should be subclassed by user code.
|
139
|
+
def receive_binary_data data
|
140
|
+
# no-op
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# $Id: stomp.rb 488 2007-07-30 05:09:40Z blackhedd $
|
2
|
+
#
|
3
|
+
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
|
+
# Homepage:: http://rubyeventmachine.com
|
5
|
+
# Date:: 15 November 2006
|
6
|
+
#
|
7
|
+
# See EventMachine and EventMachine::Connection for documentation and
|
8
|
+
# usage examples.
|
9
|
+
#
|
10
|
+
#----------------------------------------------------------------------------
|
11
|
+
#
|
12
|
+
# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
13
|
+
# Gmail: blackhedd
|
14
|
+
#
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
16
|
+
# it under the terms of either: 1) the GNU General Public License
|
17
|
+
# as published by the Free Software Foundation; either version 2 of the
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
+
#
|
20
|
+
# See the file COPYING for complete licensing information.
|
21
|
+
#
|
22
|
+
#---------------------------------------------------------------------------
|
23
|
+
#
|
24
|
+
#
|
25
|
+
#
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
module EventMachine
|
30
|
+
module Protocols
|
31
|
+
|
32
|
+
# Implements Stomp (http://docs.codehaus.org/display/STOMP/Protocol).
|
33
|
+
#
|
34
|
+
module Stomp
|
35
|
+
include LineText2
|
36
|
+
|
37
|
+
class Message
|
38
|
+
attr_accessor :command, :header, :body
|
39
|
+
def initialize
|
40
|
+
@header = {}
|
41
|
+
@state = :precommand
|
42
|
+
@content_length = nil
|
43
|
+
end
|
44
|
+
def consume_line line
|
45
|
+
if @state == :precommand
|
46
|
+
unless line =~ /\A\s*\Z/
|
47
|
+
@command = line
|
48
|
+
@state = :headers
|
49
|
+
end
|
50
|
+
elsif @state == :headers
|
51
|
+
if line == ""
|
52
|
+
if @content_length
|
53
|
+
yield( [:sized_text, @content_length+1] )
|
54
|
+
else
|
55
|
+
@state = :body
|
56
|
+
yield( [:unsized_text] )
|
57
|
+
end
|
58
|
+
elsif line =~ /\A([^:]+):(.+)\Z/
|
59
|
+
k = $1.dup.strip
|
60
|
+
v = $2.dup.strip
|
61
|
+
@header[k] = v
|
62
|
+
if k == "content-length"
|
63
|
+
@content_length = v.to_i
|
64
|
+
end
|
65
|
+
else
|
66
|
+
# This is a protocol error. How to signal it?
|
67
|
+
end
|
68
|
+
elsif @state == :body
|
69
|
+
@body = line
|
70
|
+
yield( [:dispatch] )
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def send_frame verb, headers={}, body=""
|
76
|
+
ary = [verb, "\n"]
|
77
|
+
headers.each {|k,v| ary << "#{k}:#{v}\n" }
|
78
|
+
ary << "content-length: #{body.to_s.length}\n"
|
79
|
+
ary << "content-type: text/plain; charset=UTF-8\n"
|
80
|
+
ary << "\n"
|
81
|
+
ary << body.to_s
|
82
|
+
ary << "\0"
|
83
|
+
send_data ary.join
|
84
|
+
end
|
85
|
+
|
86
|
+
def receive_line line
|
87
|
+
@stomp_initialized || init_message_reader
|
88
|
+
@stomp_message.consume_line(line) {|outcome|
|
89
|
+
if outcome.first == :sized_text
|
90
|
+
set_text_mode outcome[1]
|
91
|
+
elsif outcome.first == :unsized_text
|
92
|
+
set_delimiter "\0"
|
93
|
+
elsif outcome.first == :dispatch
|
94
|
+
receive_msg(@stomp_message) if respond_to?(:receive_msg)
|
95
|
+
init_message_reader
|
96
|
+
end
|
97
|
+
}
|
98
|
+
end
|
99
|
+
def receive_binary_data data
|
100
|
+
@stomp_message.body = data[0..-2]
|
101
|
+
receive_msg(@stomp_message) if respond_to?(:receive_msg)
|
102
|
+
init_message_reader
|
103
|
+
end
|
104
|
+
|
105
|
+
def init_message_reader
|
106
|
+
@stomp_initialized = true
|
107
|
+
set_delimiter "\n"
|
108
|
+
set_line_mode
|
109
|
+
@stomp_message = Message.new
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# STOMP verbs
|
114
|
+
def connect parms={}
|
115
|
+
send_frame "CONNECT", parms
|
116
|
+
end
|
117
|
+
def send destination, body, parms={}
|
118
|
+
send_frame "SEND", parms.merge( :destination=>destination ), body.to_s
|
119
|
+
end
|
120
|
+
def subscribe dest, ack=false
|
121
|
+
send_frame "SUBSCRIBE", {:destination=>dest, :ack=>(ack ? "client" : "auto")}
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
data/tests/test_basic.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: test_basic.rb
|
1
|
+
# $Id: test_basic.rb 452 2007-07-21 13:35:16Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -44,6 +44,8 @@ class TestBasic < Test::Unit::TestCase
|
|
44
44
|
assert_equal( :pure_ruby, lt )
|
45
45
|
when :extension
|
46
46
|
assert_equal( :extension, lt )
|
47
|
+
when :java
|
48
|
+
assert_equal( :java, lt )
|
47
49
|
else
|
48
50
|
assert_equal( :extension, lt )
|
49
51
|
end
|
@@ -74,19 +76,19 @@ class TestBasic < Test::Unit::TestCase
|
|
74
76
|
|
75
77
|
#-------------------------------------
|
76
78
|
|
77
|
-
# This test
|
79
|
+
# This test once threw an already-running exception.
|
78
80
|
module Trivial
|
79
81
|
def post_init
|
80
|
-
|
82
|
+
EventMachine.stop
|
81
83
|
end
|
82
84
|
end
|
83
85
|
|
84
86
|
def test_server
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
87
|
+
EventMachine.run {
|
88
|
+
EventMachine.start_server "localhost", 9000, Trivial
|
89
|
+
EventMachine.connect "localhost", 9000
|
90
|
+
}
|
91
|
+
assert( true ) # make sure it halts
|
90
92
|
end
|
91
93
|
|
92
94
|
#--------------------------------------
|
data/tests/test_epoll.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: test_epoll.rb
|
1
|
+
# $Id: test_epoll.rb 449 2007-07-21 00:15:30Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -67,11 +67,14 @@ class TestEpoll < Test::Unit::TestCase
|
|
67
67
|
# We can set the rlimit/nofile of a process but we can only set it
|
68
68
|
# higher if we're running as root.
|
69
69
|
# On most systems, the default value is 1024.
|
70
|
+
# Java doesn't (currently) implement this.
|
70
71
|
def test_rlimit
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
unless RUBY_PLATFORM =~ /java/
|
73
|
+
a = EM.set_descriptor_table_size
|
74
|
+
assert( a <= 1024 )
|
75
|
+
a = EM.set_descriptor_table_size( 1024 )
|
76
|
+
assert( a == 1024 )
|
77
|
+
end
|
75
78
|
end
|
76
79
|
|
77
80
|
# Run a high-volume version of this test by kicking the number of connections
|
data/tests/test_ltp.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: test_ltp.rb
|
1
|
+
# $Id: test_ltp.rb 448 2007-07-21 00:15:05Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -43,6 +43,9 @@ class TestLineAndTextProtocol < Test::Unit::TestCase
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def test_simple_lines
|
46
|
+
# THIS TEST CURRENTLY FAILS IN JRUBY.
|
47
|
+
assert( RUBY_PLATFORM !~ /java/ )
|
48
|
+
|
46
49
|
lines_received = []
|
47
50
|
Thread.abort_on_exception = true
|
48
51
|
EventMachine.run {
|
@@ -72,6 +75,9 @@ class TestLineAndTextProtocol < Test::Unit::TestCase
|
|
72
75
|
end
|
73
76
|
|
74
77
|
def test_overlength_lines
|
78
|
+
# THIS TEST CURRENTLY FAILS IN JRUBY.
|
79
|
+
assert( RUBY_PLATFORM !~ /java/ )
|
80
|
+
|
75
81
|
lines_received = []
|
76
82
|
Thread.abort_on_exception = true
|
77
83
|
EventMachine.run {
|
data/tests/test_ltp2.rb
ADDED
@@ -0,0 +1,260 @@
|
|
1
|
+
# $Id: test_ltp2.rb 486 2007-07-29 17:15:12Z blackhedd $
|
2
|
+
#
|
3
|
+
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
|
+
# Homepage:: http://rubyeventmachine.com
|
5
|
+
# Date:: 8 April 2006
|
6
|
+
#
|
7
|
+
# See EventMachine and EventMachine::Connection for documentation and
|
8
|
+
# usage examples.
|
9
|
+
#
|
10
|
+
#----------------------------------------------------------------------------
|
11
|
+
#
|
12
|
+
# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
13
|
+
# Gmail: blackhedd
|
14
|
+
#
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
16
|
+
# it under the terms of either: 1) the GNU General Public License
|
17
|
+
# as published by the Free Software Foundation; either version 2 of the
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
+
#
|
20
|
+
# See the file COPYING for complete licensing information.
|
21
|
+
#
|
22
|
+
#---------------------------------------------------------------------------
|
23
|
+
#
|
24
|
+
#
|
25
|
+
#
|
26
|
+
#
|
27
|
+
|
28
|
+
$:.unshift "../lib"
|
29
|
+
require 'eventmachine'
|
30
|
+
|
31
|
+
# TODO!!! Need tests for overlength headers and text bodies.
|
32
|
+
|
33
|
+
class TestLineText2 < Test::Unit::TestCase
|
34
|
+
|
35
|
+
# Run each of these tests two ways: passing in the whole test-dataset in one chunk,
|
36
|
+
# and passing it in one character at a time.
|
37
|
+
|
38
|
+
class Basic
|
39
|
+
include EM::Protocols::LineText2
|
40
|
+
attr_reader :lines
|
41
|
+
def receive_line line
|
42
|
+
(@lines ||= []) << line
|
43
|
+
end
|
44
|
+
end
|
45
|
+
def test_basic
|
46
|
+
testdata = "Line 1\nLine 2\r\nLine 3\n"
|
47
|
+
|
48
|
+
a = Basic.new
|
49
|
+
a.receive_data testdata
|
50
|
+
assert_equal( ["Line 1", "Line 2", "Line 3"], a.lines )
|
51
|
+
|
52
|
+
a = Basic.new
|
53
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
54
|
+
assert_equal( ["Line 1", "Line 2", "Line 3"], a.lines )
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
class ChangeDelimiter
|
59
|
+
include EM::Protocols::LineText2
|
60
|
+
attr_reader :lines
|
61
|
+
def initialize *args
|
62
|
+
super
|
63
|
+
@delim = "A"
|
64
|
+
set_delimiter @delim
|
65
|
+
end
|
66
|
+
def receive_line line
|
67
|
+
(@lines ||= []) << line
|
68
|
+
set_delimiter( @delim.succ! )
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_change_delimiter
|
73
|
+
testdata = %Q(LineaALinebBLinecCLinedD)
|
74
|
+
|
75
|
+
a = ChangeDelimiter.new
|
76
|
+
a.receive_data testdata
|
77
|
+
assert_equal( ["Linea", "Lineb", "Linec", "Lined"], a.lines )
|
78
|
+
|
79
|
+
a = ChangeDelimiter.new
|
80
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
81
|
+
assert_equal( ["Linea", "Lineb", "Linec", "Lined"], a.lines )
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
#--
|
86
|
+
# Test two lines followed by an empty line, ten bytes of binary data, then
|
87
|
+
# two more lines.
|
88
|
+
|
89
|
+
class Binary
|
90
|
+
include EM::Protocols::LineText2
|
91
|
+
attr_reader :lines, :body
|
92
|
+
def initialize *args
|
93
|
+
super
|
94
|
+
@lines = []
|
95
|
+
@body = nil
|
96
|
+
end
|
97
|
+
def receive_line ln
|
98
|
+
if ln == ""
|
99
|
+
set_text_mode 10
|
100
|
+
else
|
101
|
+
@lines << ln
|
102
|
+
end
|
103
|
+
end
|
104
|
+
def receive_binary_data data
|
105
|
+
@body = data
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_binary
|
110
|
+
testdata = %Q(Line 1
|
111
|
+
Line 2
|
112
|
+
|
113
|
+
0000000000Line 3
|
114
|
+
Line 4
|
115
|
+
)
|
116
|
+
|
117
|
+
a = Binary.new
|
118
|
+
a.receive_data testdata
|
119
|
+
assert_equal( ["Line 1", "Line 2", "Line 3", "Line 4"], a.lines)
|
120
|
+
assert_equal( "0000000000", a.body )
|
121
|
+
|
122
|
+
a = Binary.new
|
123
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
124
|
+
assert_equal( ["Line 1", "Line 2", "Line 3", "Line 4"], a.lines)
|
125
|
+
assert_equal( "0000000000", a.body )
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
# Test unsized binary data. The expectation is that each chunk of it
|
130
|
+
# will be passed to us as it it received.
|
131
|
+
class UnsizedBinary
|
132
|
+
include EM::Protocols::LineText2
|
133
|
+
attr_reader :n_calls, :body
|
134
|
+
def initialize *args
|
135
|
+
super
|
136
|
+
set_text_mode
|
137
|
+
end
|
138
|
+
def receive_binary_data data
|
139
|
+
@n_calls ||= 0
|
140
|
+
@n_calls += 1
|
141
|
+
(@body ||= "") << data
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_unsized_binary
|
146
|
+
testdata = "X\0" * 1000
|
147
|
+
|
148
|
+
a = UnsizedBinary.new
|
149
|
+
a.receive_data testdata
|
150
|
+
assert_equal( 1, a.n_calls )
|
151
|
+
assert_equal( testdata, a.body )
|
152
|
+
|
153
|
+
a = UnsizedBinary.new
|
154
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
155
|
+
assert_equal( 2000, a.n_calls )
|
156
|
+
assert_equal( testdata, a.body )
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
# Test binary data with a "throw back" into line-mode.
|
161
|
+
class ThrowBack
|
162
|
+
include EM::Protocols::LineText2
|
163
|
+
attr_reader :headers
|
164
|
+
def initialize *args
|
165
|
+
super
|
166
|
+
@headers = []
|
167
|
+
@n_bytes = 0
|
168
|
+
set_text_mode
|
169
|
+
end
|
170
|
+
def receive_binary_data data
|
171
|
+
wanted = 25 - @n_bytes
|
172
|
+
will_take = if data.length > wanted
|
173
|
+
data.length - wanted
|
174
|
+
else
|
175
|
+
data.length
|
176
|
+
end
|
177
|
+
@n_bytes += will_take
|
178
|
+
|
179
|
+
if @n_bytes == 25
|
180
|
+
set_line_mode( data[will_take..-1] )
|
181
|
+
end
|
182
|
+
end
|
183
|
+
def receive_line ln
|
184
|
+
@headers << ln
|
185
|
+
end
|
186
|
+
end
|
187
|
+
def test_throw_back
|
188
|
+
testdata = "Line\n" * 10
|
189
|
+
|
190
|
+
a = ThrowBack.new
|
191
|
+
a.receive_data testdata
|
192
|
+
assert_equal( ["Line"] * 5, a.headers )
|
193
|
+
|
194
|
+
a = ThrowBack.new
|
195
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
196
|
+
assert_equal( ["Line"] * 5, a.headers )
|
197
|
+
end
|
198
|
+
|
199
|
+
# Test multi-character line delimiters.
|
200
|
+
# Also note that the test data has a "tail" with no delimiter, that will be
|
201
|
+
# discarded, but cf. the BinaryTail test.
|
202
|
+
# TODO!!! This test doesn't work in the byte-by-byte case.
|
203
|
+
class Multichar
|
204
|
+
include EM::Protocols::LineText2
|
205
|
+
attr_reader :lines
|
206
|
+
def initialize *args
|
207
|
+
super
|
208
|
+
@lines = []
|
209
|
+
set_delimiter "012"
|
210
|
+
end
|
211
|
+
def receive_line ln
|
212
|
+
@lines << ln
|
213
|
+
end
|
214
|
+
end
|
215
|
+
def test_multichar
|
216
|
+
testdata = "Line012Line012Line012Line"
|
217
|
+
|
218
|
+
a = Multichar.new
|
219
|
+
a.receive_data testdata
|
220
|
+
assert_equal( ["Line"]*3, a.lines )
|
221
|
+
|
222
|
+
a = Multichar.new
|
223
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
224
|
+
# DOESN'T WORK in this case. Multi-character delimiters are broken.
|
225
|
+
#assert_equal( ["Line"]*3, a.lines )
|
226
|
+
end
|
227
|
+
|
228
|
+
# Test a binary "tail," when a sized binary transfer doesn't complete because
|
229
|
+
# of an unbind. We get a partial result.
|
230
|
+
class BinaryTail
|
231
|
+
include EM::Protocols::LineText2
|
232
|
+
attr_reader :data
|
233
|
+
def initialize *args
|
234
|
+
super
|
235
|
+
@data = ""
|
236
|
+
set_text_mode 1000
|
237
|
+
end
|
238
|
+
def receive_binary_data data
|
239
|
+
# we expect to get all the data in one chunk, even in the byte-by-byte case,
|
240
|
+
# because sized transfers by definition give us exactly one call to
|
241
|
+
# #receive_binary_data.
|
242
|
+
@data = data
|
243
|
+
end
|
244
|
+
end
|
245
|
+
def test_binary_tail
|
246
|
+
testdata = "0" * 500
|
247
|
+
|
248
|
+
a = BinaryTail.new
|
249
|
+
a.receive_data testdata
|
250
|
+
a.unbind
|
251
|
+
assert_equal( "0" * 500, a.data )
|
252
|
+
|
253
|
+
a = BinaryTail.new
|
254
|
+
testdata.length.times {|i| a.receive_data( testdata[i...i+1] ) }
|
255
|
+
a.unbind
|
256
|
+
assert_equal( "0" * 500, a.data )
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
|