stomper 2.0.1 → 2.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/CHANGELOG.md +28 -0
- data/README.md +1 -17
- data/features/protocol_version_negotiation.feature +6 -6
- data/features/steps/{acking_messages_steps.rb → ack_and_nack_steps.rb} +9 -1
- data/features/steps/broker_steps.rb +52 -0
- data/features/steps/client_steps.rb +137 -0
- data/features/steps/{receipts_steps.rb → receipt_steps.rb} +0 -0
- data/features/steps/{scopes_steps.rb → scope_steps.rb} +0 -16
- data/features/steps/subscription_steps.rb +80 -0
- data/lib/stomper/connection.rb +29 -29
- data/lib/stomper/receipt_manager.rb +5 -0
- data/lib/stomper/subscription_manager.rb +8 -3
- data/lib/stomper/version.rb +1 -1
- data/spec/stomper/connection_spec.rb +16 -1
- data/spec/stomper/frame_serializer_spec.rb +299 -280
- data/spec/stomper/subscription_manager_spec.rb +2 -3
- data/spec/stomper_spec.rb +0 -1
- data/spec/support/frame_header_matchers.rb +25 -0
- metadata +17 -60
- data/features/steps/disconnecting_steps.rb +0 -8
- data/features/steps/establish_connection_steps.rb +0 -77
- data/features/steps/frame_transmission_steps.rb +0 -40
- data/features/steps/protocol_version_negotiation_steps.rb +0 -15
- data/features/steps/secure_connections_steps.rb +0 -43
- data/features/steps/send_and_message_steps.rb +0 -35
- data/features/steps/subscribing_steps.rb +0 -36
- data/features/steps/threaded_receiver_steps.rb +0 -8
- data/features/steps/transactions_steps.rb +0 -0
- data/spec/stomper/frame_serializer_1.8_spec.rb +0 -318
@@ -2,313 +2,332 @@
|
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
4
|
module Stomper
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
5
|
+
describe FrameSerializer do
|
6
|
+
before(:each) do
|
7
|
+
@messages = {
|
8
|
+
:content_type_and_charset => "MESSAGE\ncontent-type:text/plain; charset=ISO-8859-1\ncontent-length:6\na-header: padded \n\nh\xEBllo!\000",
|
9
|
+
:escaped_headers => "MESSAGE\ncontent-type:text/plain;charset=UTF-8\ncontent-length:7\na\\nspecial\\chead\\\\cer: padded\\c and using\\nspecial\\\\\\\\\\\\ncharacters \n\nh\xC3\xABllo!\000",
|
10
|
+
:no_content_length => "MESSAGE\ncontent-type:text/plain\n\nh\xC3\xABllo!\000",
|
11
|
+
:repeated_headers => "MESSAGE\ncontent-type:text/plain\nrepeated header:a value\nrepeated header:alternate value\n\nh\xC3\xABllo!\000",
|
12
|
+
:non_text_content_type => "MESSAGE\ncontent-type:not-text/other\n\nh\xC3\xABllo!\000",
|
13
|
+
:no_content_type => "MESSAGE\n\nh\xC3\xABllo!\000",
|
14
|
+
:invalid_content_length => "MESSAGE\ncontent-length:4\n\n12345\000",
|
15
|
+
:invalid_header_character => "MESSAGE\ngrandpa:he was:anti\n\n12345\000",
|
16
|
+
:invalid_header_sequence => "MESSAGE\ngrandpa:he was\\ranti\n\n12345\000",
|
17
|
+
:malformed_header => "MESSAGE\nearth_below_us\nfloating:weightless\n\n12345\000",
|
18
|
+
:dangling_header_sequence => "MESSAGE\ngrandpa:he was anti\\\n\n12345\000",
|
19
|
+
}
|
20
|
+
|
21
|
+
@frames = {
|
22
|
+
:common => ::Stomper::Frame.new('FRAME', {}, 'body of message'),
|
23
|
+
:no_headers => ::Stomper::Frame.new('FRAME', {}, 'body of message'),
|
24
|
+
:no_body => ::Stomper::Frame.new('FRAME', {}),
|
25
|
+
:no_command => ::Stomper::Frame.new,
|
26
|
+
:header_name_with_linefeed => ::Stomper::Frame.new('FRAME', { "a\ntest\nheader" => "va\\lue : is\n\nme"}),
|
27
|
+
:header_name_with_colon => ::Stomper::Frame.new('FRAME', { "a:test:header" => "va\\lue : is\n\nme"}),
|
28
|
+
:header_name_with_backslash => ::Stomper::Frame.new('FRAME', { "a\\test\\header" => "va\\lue : is\n\nme"}),
|
29
|
+
:binary_body_no_content_type => ::Stomper::Frame.new('FRAME', {}, 'body of message'),
|
30
|
+
:charset_header_text_body => ::Stomper::Frame.new('FRAME', {:'content-type' => 'text/plain; param="value";charset=ISO-8859-1'}, 'body of message'),
|
31
|
+
:charset_header_binary_body => ::Stomper::Frame.new('FRAME', {:'content-type' => 'application/pdf; param="value";charset=ISO-8859-1'}, 'body of message')
|
32
|
+
}
|
33
|
+
# Curse Ruby 1.8.7 and it's unordered hashes!
|
34
|
+
@frames[:common][:header_1] = 'value 1'
|
35
|
+
@frames[:common][:header_2] = '3'
|
36
|
+
@frames[:common][:header_3] = ''
|
37
|
+
@frames[:common][:'content-type'] = 'text/plain'
|
38
|
+
@frames[:no_body][:header_1] = 'val'
|
39
|
+
@frames[:no_body][:musical] = ''
|
40
|
+
@frames[:no_body][:offering] = '4'
|
41
|
+
if RUBY_VERSION >= "1.9"
|
21
42
|
@messages.each { |k, v| v.force_encoding('ASCII-8BIT') }
|
43
|
+
@frames[:no_headers].body = @frames[:no_headers].body.encode('ISO-8859-1')
|
44
|
+
@frames[:binary_body_no_content_type].body = @frames[:binary_body_no_content_type].body.encode('ASCII-8BIT')
|
45
|
+
@frames[:charset_header_binary_body].body = @frames[:charset_header_binary_body].body.encode('ASCII-8BIT')
|
46
|
+
@frames[:charset_header_text_body].body = @frames[:charset_header_text_body].body.encode('UTF-8')
|
47
|
+
end
|
48
|
+
@frame_io = StringIO.new
|
49
|
+
@frame_serializer = FrameSerializer.new(@frame_io)
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "thread safety" do
|
53
|
+
before(:each) do
|
54
|
+
@frame_serializer = FrameSerializer.new(mock('frame io'))
|
55
|
+
end
|
56
|
+
it "should synchronize writing to the underlying IO" do
|
57
|
+
first_called = false
|
58
|
+
call_next = false
|
59
|
+
ordered = []
|
60
|
+
@frame_serializer.stub!(:__write_frame__).and_return do |f|
|
61
|
+
first_called = true
|
62
|
+
ordered << 1
|
63
|
+
Thread.stop
|
64
|
+
ordered << 2
|
65
|
+
f
|
66
|
+
end
|
67
|
+
|
68
|
+
thread_1 = Thread.new do
|
69
|
+
@frame_serializer.write_frame(mock('frame'))
|
70
|
+
end
|
71
|
+
thread_2 = Thread.new do
|
72
|
+
Thread.pass until call_next
|
73
|
+
Thread.pass
|
74
|
+
thread_1.run
|
75
|
+
end
|
76
|
+
Thread.pass until first_called
|
77
|
+
call_next = true
|
22
78
|
|
23
|
-
@
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
:binary_body_no_content_type => ::Stomper::Frame.new('FRAME', {}, 'body of message'.encode('ASCII-8BIT')),
|
32
|
-
:charset_header_text_body => ::Stomper::Frame.new('FRAME', {:'content-type' => 'text/plain; param="value";charset=ISO-8859-1'}, 'body of message'.encode('UTF-8')),
|
33
|
-
:charset_header_binary_body => ::Stomper::Frame.new('FRAME', {:'content-type' => 'application/pdf; param="value";charset=ISO-8859-1'}, 'body of message'.encode('ASCII-8BIT'))
|
34
|
-
}
|
35
|
-
@frame_io = StringIO.new
|
36
|
-
@frame_serializer = FrameSerializer.new(@frame_io)
|
79
|
+
@frame_serializer.stub!(:__write_frame__).and_return do |f|
|
80
|
+
ordered << 3
|
81
|
+
f
|
82
|
+
end
|
83
|
+
@frame_serializer.write_frame(mock('frame'))
|
84
|
+
thread_1.join
|
85
|
+
thread_2.join
|
86
|
+
ordered.should == [1, 2, 3]
|
37
87
|
end
|
38
88
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
first_called =
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
ordered << 1
|
50
|
-
Thread.stop
|
51
|
-
ordered << 2
|
52
|
-
f
|
53
|
-
end
|
54
|
-
|
55
|
-
thread_1 = Thread.new do
|
56
|
-
@frame_serializer.write_frame(mock('frame'))
|
57
|
-
end
|
58
|
-
thread_2 = Thread.new do
|
59
|
-
Thread.pass until call_next
|
60
|
-
Thread.pass
|
61
|
-
thread_1.run
|
62
|
-
end
|
63
|
-
Thread.pass until first_called
|
64
|
-
call_next = true
|
65
|
-
|
66
|
-
@frame_serializer.stub!(:__write_frame__).and_return do |f|
|
67
|
-
ordered << 3
|
68
|
-
f
|
69
|
-
end
|
70
|
-
@frame_serializer.write_frame(mock('frame'))
|
71
|
-
thread_1.join
|
72
|
-
thread_2.join
|
73
|
-
ordered.should == [1, 2, 3]
|
89
|
+
it "should synchronize reading from the underlying IO" do
|
90
|
+
first_called = false
|
91
|
+
call_next = false
|
92
|
+
ordered = []
|
93
|
+
@frame_serializer.stub!(:__read_frame__).and_return do
|
94
|
+
first_called = true
|
95
|
+
ordered << 1
|
96
|
+
Thread.stop
|
97
|
+
ordered << 2
|
98
|
+
mock('frame 1')
|
74
99
|
end
|
75
100
|
|
76
|
-
|
77
|
-
first_called = false
|
78
|
-
call_next = false
|
79
|
-
ordered = []
|
80
|
-
@frame_serializer.stub!(:__read_frame__).and_return do
|
81
|
-
first_called = true
|
82
|
-
ordered << 1
|
83
|
-
Thread.stop
|
84
|
-
ordered << 2
|
85
|
-
mock('frame 1')
|
86
|
-
end
|
87
|
-
|
88
|
-
thread_1 = Thread.new do
|
89
|
-
@frame_serializer.read_frame
|
90
|
-
end
|
91
|
-
thread_2 = Thread.new do
|
92
|
-
Thread.pass until call_next
|
93
|
-
Thread.pass
|
94
|
-
thread_1.run
|
95
|
-
end
|
96
|
-
Thread.pass until first_called
|
97
|
-
call_next = true
|
98
|
-
|
99
|
-
@frame_serializer.stub!(:__read_frame__).and_return do
|
100
|
-
ordered << 3
|
101
|
-
mock('frame 2')
|
102
|
-
end
|
101
|
+
thread_1 = Thread.new do
|
103
102
|
@frame_serializer.read_frame
|
104
|
-
thread_1.join
|
105
|
-
thread_2.join
|
106
|
-
ordered.should == [1, 2, 3]
|
107
103
|
end
|
104
|
+
thread_2 = Thread.new do
|
105
|
+
Thread.pass until call_next
|
106
|
+
Thread.pass
|
107
|
+
thread_1.run
|
108
|
+
end
|
109
|
+
Thread.pass until first_called
|
110
|
+
call_next = true
|
108
111
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
ordered = []
|
113
|
-
@frame_serializer.stub!(:__write_frame__).and_return do |f|
|
114
|
-
first_called = true
|
115
|
-
ordered << 1
|
116
|
-
Thread.stop
|
117
|
-
ordered << 2
|
118
|
-
f
|
119
|
-
end
|
120
|
-
@frame_serializer.stub!(:__read_frame__).and_return do
|
121
|
-
ordered << 3
|
122
|
-
mock('frame 2')
|
123
|
-
end
|
124
|
-
|
125
|
-
thread_1 = Thread.new do
|
126
|
-
@frame_serializer.write_frame(mock('frame'))
|
127
|
-
end
|
128
|
-
thread_2 = Thread.new do
|
129
|
-
Thread.pass until call_next
|
130
|
-
Thread.pass
|
131
|
-
thread_1.run
|
132
|
-
end
|
133
|
-
Thread.pass until first_called
|
134
|
-
call_next = true
|
135
|
-
@frame_serializer.read_frame
|
136
|
-
thread_1.join
|
137
|
-
thread_2.join
|
138
|
-
ordered.should == [1, 3, 2]
|
112
|
+
@frame_serializer.stub!(:__read_frame__).and_return do
|
113
|
+
ordered << 3
|
114
|
+
mock('frame 2')
|
139
115
|
end
|
116
|
+
@frame_serializer.read_frame
|
117
|
+
thread_1.join
|
118
|
+
thread_2.join
|
119
|
+
ordered.should == [1, 2, 3]
|
140
120
|
end
|
141
121
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
122
|
+
it "should not make reading and writing mutually exclusive" do
|
123
|
+
first_called = false
|
124
|
+
call_next = false
|
125
|
+
ordered = []
|
126
|
+
@frame_serializer.stub!(:__write_frame__).and_return do |f|
|
127
|
+
first_called = true
|
128
|
+
ordered << 1
|
129
|
+
Thread.stop
|
130
|
+
ordered << 2
|
131
|
+
f
|
132
|
+
end
|
133
|
+
@frame_serializer.stub!(:__read_frame__).and_return do
|
134
|
+
ordered << 3
|
135
|
+
mock('frame 2')
|
147
136
|
end
|
148
137
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
138
|
+
thread_1 = Thread.new do
|
139
|
+
@frame_serializer.write_frame(mock('frame'))
|
140
|
+
end
|
141
|
+
thread_2 = Thread.new do
|
142
|
+
Thread.pass until call_next
|
143
|
+
Thread.pass
|
144
|
+
thread_1.run
|
145
|
+
end
|
146
|
+
Thread.pass until first_called
|
147
|
+
call_next = true
|
148
|
+
@frame_serializer.read_frame
|
149
|
+
thread_1.join
|
150
|
+
thread_2.join
|
151
|
+
ordered.should == [1, 3, 2]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "Protocol 1.0" do
|
156
|
+
it "should not have extended the V1_1 mixin" do
|
157
|
+
::Stomper::FrameSerializer::EXTEND_BY_VERSION['1.1'].each do |mod|
|
158
|
+
@frame_serializer.should_not be_a_kind_of(mod)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "writing frames" do
|
163
|
+
it "should properly serialize a common frame" do
|
164
|
+
@frame_serializer.write_frame(@frames[:common])
|
165
|
+
@frame_io.string.should == "FRAME\nheader_1:value 1\nheader_2:3\nheader_3:\ncontent-type:text/plain;charset=UTF-8\ncontent-length:15\n\nbody of message\000"
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should properly serialize a frame without headers" do
|
169
|
+
@frame_serializer.write_frame(@frames[:no_headers])
|
170
|
+
expected = RUBY_VERSION >= '1.9' ? "FRAME\ncontent-type:text/plain;charset=ISO-8859-1\ncontent-length:15\n\nbody of message\000" :
|
171
|
+
"FRAME\ncontent-length:15\n\nbody of message\000"
|
172
|
+
@frame_io.string.should == expected
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should properly serialize a frame without a body" do
|
176
|
+
@frame_serializer.write_frame(@frames[:no_body])
|
177
|
+
@frame_io.string.should == "FRAME\nheader_1:val\nmusical:\noffering:4\n\n\000"
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should properly serialize a frame without a command as a new line" do
|
181
|
+
@frame_serializer.write_frame(@frames[:no_command])
|
182
|
+
@frame_io.string.should == "\n"
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should properly drop LF from header names and values" do
|
186
|
+
@frame_serializer.write_frame(@frames[:header_name_with_linefeed])
|
187
|
+
@frame_io.string.should == "FRAME\natestheader:va\\lue : isme\n\n\000"
|
188
|
+
end
|
154
189
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
190
|
+
it "should not escape backslash characters in header names or values" do
|
191
|
+
@frame_serializer.write_frame(@frames[:header_name_with_backslash])
|
192
|
+
@frame_io.string.should == "FRAME\na\\test\\header:va\\lue : isme\n\n\000"
|
193
|
+
end
|
159
194
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
195
|
+
it "should drop colons in header names, but leave them alone in values" do
|
196
|
+
@frame_serializer.write_frame(@frames[:header_name_with_colon])
|
197
|
+
@frame_io.string.should == "FRAME\natestheader:va\\lue : isme\n\n\000"
|
198
|
+
end
|
164
199
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
200
|
+
it "should not generate a content-type header if the encoding is binary" do
|
201
|
+
@frame_serializer.write_frame(@frames[:binary_body_no_content_type])
|
202
|
+
@frame_io.string.should == "FRAME\ncontent-length:15\n\nbody of message\000"
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should overwrite the charset parameter with the encoding when the body is text" do
|
206
|
+
@frame_serializer.write_frame(@frames[:charset_header_text_body])
|
207
|
+
expected = RUBY_VERSION >= '1.9' ? "FRAME\ncontent-type:text/plain; param=\"value\";charset=UTF-8\ncontent-length:15\n\nbody of message\000" :
|
208
|
+
"FRAME\ncontent-type:text/plain; param=\"value\";charset=ISO-8859-1\ncontent-length:15\n\nbody of message\000"
|
209
|
+
@frame_io.string.should == expected
|
210
|
+
end
|
169
211
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
it "should not escape backslash characters in header names or values" do
|
176
|
-
@frame_serializer.write_frame(@frames[:header_name_with_backslash])
|
177
|
-
@frame_io.string.should == "FRAME\na\\test\\header:va\\lue : isme\n\n\000"
|
178
|
-
end
|
179
|
-
|
180
|
-
it "should drop colons in header names, but leave them alone in values" do
|
181
|
-
@frame_serializer.write_frame(@frames[:header_name_with_colon])
|
182
|
-
@frame_io.string.should == "FRAME\natestheader:va\\lue : isme\n\n\000"
|
183
|
-
end
|
184
|
-
|
185
|
-
it "should not generate a content-type header if the encoding is binary" do
|
186
|
-
@frame_serializer.write_frame(@frames[:binary_body_no_content_type])
|
187
|
-
@frame_io.string.should == "FRAME\ncontent-length:15\n\nbody of message\000"
|
188
|
-
end
|
189
|
-
|
190
|
-
it "should overwrite the charset parameter with the encoding when the body is text" do
|
191
|
-
@frame_serializer.write_frame(@frames[:charset_header_text_body])
|
192
|
-
@frame_io.string.should == "FRAME\ncontent-type:text/plain; param=\"value\";charset=UTF-8\ncontent-length:15\n\nbody of message\000"
|
193
|
-
end
|
194
|
-
|
195
|
-
it "should omit the charset parameter when the content-type is not text/* and the encoding is binary" do
|
196
|
-
@frame_serializer.write_frame(@frames[:charset_header_binary_body])
|
197
|
-
@frame_io.string.should == "FRAME\ncontent-type:application/pdf; param=\"value\"\ncontent-length:15\n\nbody of message\000"
|
198
|
-
end
|
212
|
+
it "should omit the charset parameter when the content-type is not text/* and the encoding is binary" do
|
213
|
+
@frame_serializer.write_frame(@frames[:charset_header_binary_body])
|
214
|
+
expected = RUBY_VERSION >= '1.9' ? "FRAME\ncontent-type:application/pdf; param=\"value\"\ncontent-length:15\n\nbody of message\000" :
|
215
|
+
"FRAME\ncontent-type:application/pdf; param=\"value\";charset=ISO-8859-1\ncontent-length:15\n\nbody of message\000"
|
216
|
+
@frame_io.string.should == expected
|
199
217
|
end
|
200
218
|
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "Protocol 1.1" do
|
222
|
+
before(:each) do
|
223
|
+
@frame_serializer.extend_for_protocol '1.1'
|
224
|
+
end
|
201
225
|
|
202
|
-
|
203
|
-
|
204
|
-
@frame_serializer.
|
226
|
+
it "should have extended the V1_1 mixin" do
|
227
|
+
::Stomper::FrameSerializer::EXTEND_BY_VERSION['1.1'].each do |mod|
|
228
|
+
@frame_serializer.should be_a_kind_of(mod)
|
205
229
|
end
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "writing frames" do
|
233
|
+
it "should properly serialize a common frame" do
|
234
|
+
@frame_serializer.write_frame(@frames[:common])
|
235
|
+
@frame_io.string.should == "FRAME\nheader_1:value 1\nheader_2:3\nheader_3:\ncontent-type:text/plain;charset=UTF-8\ncontent-length:15\n\nbody of message\000"
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should properly serialize a frame without headers" do
|
239
|
+
@frame_serializer.write_frame(@frames[:no_headers])
|
240
|
+
expected = RUBY_VERSION >= '1.9' ? "FRAME\ncontent-type:text/plain;charset=ISO-8859-1\ncontent-length:15\n\nbody of message\000" :
|
241
|
+
"FRAME\ncontent-length:15\n\nbody of message\000"
|
242
|
+
@frame_io.string.should == expected
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should properly serialize a frame without a body" do
|
246
|
+
@frame_serializer.write_frame(@frames[:no_body])
|
247
|
+
@frame_io.string.should == "FRAME\nheader_1:val\nmusical:\noffering:4\n\n\000"
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should properly serialize a frame without a command as a new line" do
|
251
|
+
@frame_serializer.write_frame(@frames[:no_command])
|
252
|
+
@frame_io.string.should == "\n"
|
211
253
|
end
|
212
|
-
|
213
|
-
describe "writing frames" do
|
214
|
-
it "should properly serialize a common frame" do
|
215
|
-
@frame_serializer.write_frame(@frames[:common])
|
216
|
-
@frame_io.string.should == "FRAME\nheader_1:value 1\nheader_2:3\nheader_3:\ncontent-type:text/plain;charset=UTF-8\ncontent-length:15\n\nbody of message\000"
|
217
|
-
end
|
218
254
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
255
|
+
it "should escape LF in header names and values" do
|
256
|
+
@frame_serializer.write_frame(@frames[:header_name_with_linefeed])
|
257
|
+
@frame_io.string.should == "FRAME\na\\ntest\\nheader:va\\\\lue \\c is\\n\\nme\n\n\000"
|
258
|
+
end
|
223
259
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
260
|
+
it "should escape backslashes in header names and values" do
|
261
|
+
@frame_serializer.write_frame(@frames[:header_name_with_backslash])
|
262
|
+
@frame_io.string.should == "FRAME\na\\\\test\\\\header:va\\\\lue \\c is\\n\\nme\n\n\000"
|
263
|
+
end
|
228
264
|
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
end
|
233
|
-
|
234
|
-
it "should escape LF in header names and values" do
|
235
|
-
@frame_serializer.write_frame(@frames[:header_name_with_linefeed])
|
236
|
-
@frame_io.string.should == "FRAME\na\\ntest\\nheader:va\\\\lue \\c is\\n\\nme\n\n\000"
|
237
|
-
end
|
238
|
-
|
239
|
-
it "should escape backslashes in header names and values" do
|
240
|
-
@frame_serializer.write_frame(@frames[:header_name_with_backslash])
|
241
|
-
@frame_io.string.should == "FRAME\na\\\\test\\\\header:va\\\\lue \\c is\\n\\nme\n\n\000"
|
242
|
-
end
|
243
|
-
|
244
|
-
it "should escape colons in header names and values" do
|
245
|
-
@frame_serializer.write_frame(@frames[:header_name_with_colon])
|
246
|
-
@frame_io.string.should == "FRAME\na\\ctest\\cheader:va\\\\lue \\c is\\n\\nme\n\n\000"
|
247
|
-
end
|
265
|
+
it "should escape colons in header names and values" do
|
266
|
+
@frame_serializer.write_frame(@frames[:header_name_with_colon])
|
267
|
+
@frame_io.string.should == "FRAME\na\\ctest\\cheader:va\\\\lue \\c is\\n\\nme\n\n\000"
|
248
268
|
end
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe "reading frames" do
|
272
|
+
it "should properly de-serialize a simple frame" do
|
273
|
+
@frame_io.string = @messages[:content_type_and_charset]
|
274
|
+
frame = @frame_serializer.read_frame
|
275
|
+
frame.should have_command('MESSAGE')
|
276
|
+
frame.should have_header(:'a-header', ' padded ')
|
277
|
+
frame.should have_header(:'content-length', '6')
|
278
|
+
frame.should have_header(:'content-type', 'text/plain; charset=ISO-8859-1')
|
279
|
+
frame.should have_body("hëllo!", "h\xEBllo!", 'ISO-8859-1')
|
280
|
+
frame.should have_body_encoding('ISO-8859-1')
|
281
|
+
end
|
282
|
+
it "should properly read a frame with special characters in its header" do
|
283
|
+
@frame_io.string = @messages[:escaped_headers]
|
284
|
+
frame = @frame_serializer.read_frame
|
285
|
+
frame.should have_header("a\nspecial:head\\cer", " padded: and using\nspecial\\\\\\ncharacters ")
|
286
|
+
frame.should have_body_encoding('UTF-8')
|
287
|
+
end
|
288
|
+
it "should properly read a frame with a body and no content-length" do
|
289
|
+
@frame_io.string = @messages[:no_content_length]
|
290
|
+
frame = @frame_serializer.read_frame
|
291
|
+
frame.should have_body("hëllo!", "h\xC3\xABllo!", 'UTF-8')
|
292
|
+
frame.should have_body_encoding('UTF-8')
|
293
|
+
end
|
294
|
+
it "should assume a binary charset if none is set and the content-type does not match text/*" do
|
295
|
+
@frame_io.string = @messages[:non_text_content_type]
|
296
|
+
frame = @frame_serializer.read_frame
|
297
|
+
frame.should have_body_encoding('ASCII-8BIT')
|
298
|
+
end
|
299
|
+
it "should assume a binary charset if the content-type header is not specified" do
|
300
|
+
@frame_io.string = @messages[:no_content_type]
|
301
|
+
frame = @frame_serializer.read_frame
|
302
|
+
frame.should have_body_encoding('ASCII-8BIT')
|
303
|
+
end
|
304
|
+
it "should set the value of a header to the first occurrence" do
|
305
|
+
@frame_io.string = @messages[:repeated_headers]
|
306
|
+
frame = @frame_serializer.read_frame
|
307
|
+
frame.should have_header(:'repeated header', 'a value')
|
308
|
+
end
|
309
|
+
it "should raise a malformed frame error if the frame is not properly terminated" do
|
310
|
+
@frame_io.string = @messages[:invalid_content_length]
|
311
|
+
lambda { @frame_serializer.read_frame }.should raise_error(::Stomper::Errors::MalformedFrameError)
|
312
|
+
end
|
313
|
+
# While the spec suggests that all ":" chars be replaced with "\c", ActiveMQ 5.3.2 sends
|
314
|
+
# a "session" header with a value that contains ":" chars. So, we are NOT going to
|
315
|
+
# freak out if we receive more than one ":" on a header line.
|
316
|
+
it "should not raise an error if the frame contains a header value with a raw ':'" do
|
317
|
+
@frame_io.string = @messages[:invalid_header_character]
|
318
|
+
lambda { @frame_serializer.read_frame }.should_not raise_error
|
319
|
+
end
|
320
|
+
it "should raise an invalid header esacape sequence error if the frame contains a header with an invalid escape sequence" do
|
321
|
+
@frame_io.string = @messages[:invalid_header_sequence]
|
322
|
+
lambda { @frame_serializer.read_frame }.should raise_error(::Stomper::Errors::InvalidHeaderEscapeSequenceError)
|
323
|
+
end
|
324
|
+
it "should raise an malfored header error if the frame contains an incomplete header" do
|
325
|
+
@frame_io.string = @messages[:malformed_header]
|
326
|
+
lambda { @frame_serializer.read_frame }.should raise_error(::Stomper::Errors::MalformedHeaderError)
|
327
|
+
end
|
328
|
+
it "should raise an invalid header esacape sequence error if the frame contains a header with a dangling escape sequence" do
|
329
|
+
@frame_io.string = @messages[:dangling_header_sequence]
|
330
|
+
lambda { @frame_serializer.read_frame }.should raise_error(::Stomper::Errors::InvalidHeaderEscapeSequenceError)
|
312
331
|
end
|
313
332
|
end
|
314
333
|
end
|
@@ -11,7 +11,6 @@ module Stomper
|
|
11
11
|
receipt = mock('receipt')
|
12
12
|
@connection.should_receive(:on_message)
|
13
13
|
@connection.should_receive(:on_unsubscribe)
|
14
|
-
@connection.should_receive(:on_connection_closed)
|
15
14
|
@subscription_manager = SubscriptionManager.new(@connection)
|
16
15
|
end
|
17
16
|
|
@@ -49,13 +48,13 @@ module Stomper
|
|
49
48
|
@subscription_manager.subscriptions.should be_empty
|
50
49
|
end
|
51
50
|
|
52
|
-
it "should clear out all remaining subscriptions when
|
51
|
+
it "should clear out all remaining subscriptions when cleared" do
|
53
52
|
alt_subscribe_frame = ::Stomper::Frame.new('SUBSCRIBE', {:id => '4567', :destination => '/queue/test_further'})
|
54
53
|
@subscription_manager.add(@subscribe_frame, lambda { |m| true })
|
55
54
|
@subscription_manager.add(alt_subscribe_frame, lambda { |m| true })
|
56
55
|
@subscription_manager.remove('4567')
|
57
56
|
@subscription_manager.subscriptions.map { |s| s.id }.should == ['1234']
|
58
|
-
@
|
57
|
+
@subscription_manager.clear
|
59
58
|
@subscription_manager.subscriptions.should be_empty
|
60
59
|
end
|
61
60
|
|