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