tiny_thrift 1.0.0.0

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.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/README +43 -0
  3. data/benchmark/Benchmark.thrift +24 -0
  4. data/benchmark/benchmark.rb +271 -0
  5. data/benchmark/client.rb +74 -0
  6. data/benchmark/server.rb +82 -0
  7. data/benchmark/thin_server.rb +44 -0
  8. data/ext/binary_protocol_accelerated.c +460 -0
  9. data/ext/binary_protocol_accelerated.h +20 -0
  10. data/ext/bytes.c +36 -0
  11. data/ext/bytes.h +31 -0
  12. data/ext/compact_protocol.c +635 -0
  13. data/ext/compact_protocol.h +20 -0
  14. data/ext/constants.h +96 -0
  15. data/ext/extconf.rb +32 -0
  16. data/ext/macros.h +41 -0
  17. data/ext/memory_buffer.c +134 -0
  18. data/ext/memory_buffer.h +20 -0
  19. data/ext/protocol.c +0 -0
  20. data/ext/protocol.h +0 -0
  21. data/ext/strlcpy.c +41 -0
  22. data/ext/strlcpy.h +34 -0
  23. data/ext/struct.c +688 -0
  24. data/ext/struct.h +25 -0
  25. data/ext/thrift_native.c +195 -0
  26. data/lib/thrift.rb +66 -0
  27. data/lib/thrift/bytes.rb +131 -0
  28. data/lib/thrift/client.rb +62 -0
  29. data/lib/thrift/core_ext.rb +23 -0
  30. data/lib/thrift/core_ext/fixnum.rb +29 -0
  31. data/lib/thrift/exceptions.rb +87 -0
  32. data/lib/thrift/processor.rb +57 -0
  33. data/lib/thrift/protocol/base_protocol.rb +377 -0
  34. data/lib/thrift/protocol/binary_protocol.rb +237 -0
  35. data/lib/thrift/protocol/binary_protocol_accelerated.rb +39 -0
  36. data/lib/thrift/protocol/compact_protocol.rb +434 -0
  37. data/lib/thrift/protocol/json_protocol.rb +769 -0
  38. data/lib/thrift/serializer/deserializer.rb +33 -0
  39. data/lib/thrift/serializer/serializer.rb +34 -0
  40. data/lib/thrift/server/base_server.rb +31 -0
  41. data/lib/thrift/server/mongrel_http_server.rb +60 -0
  42. data/lib/thrift/server/nonblocking_server.rb +305 -0
  43. data/lib/thrift/server/simple_server.rb +43 -0
  44. data/lib/thrift/server/thin_http_server.rb +91 -0
  45. data/lib/thrift/server/thread_pool_server.rb +75 -0
  46. data/lib/thrift/server/threaded_server.rb +47 -0
  47. data/lib/thrift/struct.rb +237 -0
  48. data/lib/thrift/struct_union.rb +192 -0
  49. data/lib/thrift/thrift_native.rb +24 -0
  50. data/lib/thrift/transport/base_server_transport.rb +37 -0
  51. data/lib/thrift/transport/base_transport.rb +109 -0
  52. data/lib/thrift/transport/buffered_transport.rb +114 -0
  53. data/lib/thrift/transport/framed_transport.rb +117 -0
  54. data/lib/thrift/transport/http_client_transport.rb +56 -0
  55. data/lib/thrift/transport/io_stream_transport.rb +39 -0
  56. data/lib/thrift/transport/memory_buffer_transport.rb +125 -0
  57. data/lib/thrift/transport/server_socket.rb +63 -0
  58. data/lib/thrift/transport/socket.rb +139 -0
  59. data/lib/thrift/transport/unix_server_socket.rb +60 -0
  60. data/lib/thrift/transport/unix_socket.rb +40 -0
  61. data/lib/thrift/types.rb +101 -0
  62. data/lib/thrift/union.rb +179 -0
  63. data/lib/tiny_thrift.rb +1 -0
  64. data/spec/ThriftSpec.thrift +183 -0
  65. data/spec/base_protocol_spec.rb +217 -0
  66. data/spec/base_transport_spec.rb +350 -0
  67. data/spec/binary_protocol_accelerated_spec.rb +42 -0
  68. data/spec/binary_protocol_spec.rb +66 -0
  69. data/spec/binary_protocol_spec_shared.rb +455 -0
  70. data/spec/bytes_spec.rb +160 -0
  71. data/spec/client_spec.rb +99 -0
  72. data/spec/compact_protocol_spec.rb +143 -0
  73. data/spec/exception_spec.rb +141 -0
  74. data/spec/http_client_spec.rb +120 -0
  75. data/spec/json_protocol_spec.rb +513 -0
  76. data/spec/nonblocking_server_spec.rb +263 -0
  77. data/spec/processor_spec.rb +80 -0
  78. data/spec/serializer_spec.rb +67 -0
  79. data/spec/server_socket_spec.rb +79 -0
  80. data/spec/server_spec.rb +147 -0
  81. data/spec/socket_spec.rb +61 -0
  82. data/spec/socket_spec_shared.rb +104 -0
  83. data/spec/spec_helper.rb +61 -0
  84. data/spec/struct_nested_containers_spec.rb +191 -0
  85. data/spec/struct_spec.rb +293 -0
  86. data/spec/thin_http_server_spec.rb +141 -0
  87. data/spec/types_spec.rb +115 -0
  88. data/spec/union_spec.rb +203 -0
  89. data/spec/unix_socket_spec.rb +107 -0
  90. metadata +313 -0
@@ -0,0 +1,217 @@
1
+ #
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ #
19
+
20
+ require 'spec_helper'
21
+
22
+ describe 'BaseProtocol' do
23
+
24
+ before(:each) do
25
+ @trans = mock("MockTransport")
26
+ @prot = Thrift::BaseProtocol.new(@trans)
27
+ end
28
+
29
+ describe Thrift::BaseProtocol do
30
+ # most of the methods are stubs, so we can ignore them
31
+
32
+ it "should make trans accessible" do
33
+ @prot.trans.should eql(@trans)
34
+ end
35
+
36
+ it 'should write out a field nicely (deprecated write_field signature)' do
37
+ @prot.should_receive(:write_field_begin).with('field', 'type', 'fid').ordered
38
+ @prot.should_receive(:write_type).with({:name => 'field', :type => 'type'}, 'value').ordered
39
+ @prot.should_receive(:write_field_end).ordered
40
+ @prot.write_field('field', 'type', 'fid', 'value')
41
+ end
42
+
43
+ it 'should write out a field nicely' do
44
+ @prot.should_receive(:write_field_begin).with('field', 'type', 'fid').ordered
45
+ @prot.should_receive(:write_type).with({:name => 'field', :type => 'type', :binary => false}, 'value').ordered
46
+ @prot.should_receive(:write_field_end).ordered
47
+ @prot.write_field({:name => 'field', :type => 'type', :binary => false}, 'fid', 'value')
48
+ end
49
+
50
+ it 'should write out the different types (deprecated write_type signature)' do
51
+ @prot.should_receive(:write_bool).with('bool').ordered
52
+ @prot.should_receive(:write_byte).with('byte').ordered
53
+ @prot.should_receive(:write_double).with('double').ordered
54
+ @prot.should_receive(:write_i16).with('i16').ordered
55
+ @prot.should_receive(:write_i32).with('i32').ordered
56
+ @prot.should_receive(:write_i64).with('i64').ordered
57
+ @prot.should_receive(:write_string).with('string').ordered
58
+ struct = mock('Struct')
59
+ struct.should_receive(:write).with(@prot).ordered
60
+ @prot.write_type(Thrift::Types::BOOL, 'bool')
61
+ @prot.write_type(Thrift::Types::BYTE, 'byte')
62
+ @prot.write_type(Thrift::Types::DOUBLE, 'double')
63
+ @prot.write_type(Thrift::Types::I16, 'i16')
64
+ @prot.write_type(Thrift::Types::I32, 'i32')
65
+ @prot.write_type(Thrift::Types::I64, 'i64')
66
+ @prot.write_type(Thrift::Types::STRING, 'string')
67
+ @prot.write_type(Thrift::Types::STRUCT, struct)
68
+ # all other types are not implemented
69
+ [Thrift::Types::STOP, Thrift::Types::VOID, Thrift::Types::MAP, Thrift::Types::SET, Thrift::Types::LIST].each do |type|
70
+ expect { @prot.write_type(type, type.to_s) }.to raise_error(NotImplementedError)
71
+ end
72
+ end
73
+
74
+ it 'should write out the different types' do
75
+ @prot.should_receive(:write_bool).with('bool').ordered
76
+ @prot.should_receive(:write_byte).with('byte').ordered
77
+ @prot.should_receive(:write_double).with('double').ordered
78
+ @prot.should_receive(:write_i16).with('i16').ordered
79
+ @prot.should_receive(:write_i32).with('i32').ordered
80
+ @prot.should_receive(:write_i64).with('i64').ordered
81
+ @prot.should_receive(:write_string).with('string').ordered
82
+ @prot.should_receive(:write_binary).with('binary').ordered
83
+ struct = mock('Struct')
84
+ struct.should_receive(:write).with(@prot).ordered
85
+ @prot.write_type({:type => Thrift::Types::BOOL}, 'bool')
86
+ @prot.write_type({:type => Thrift::Types::BYTE}, 'byte')
87
+ @prot.write_type({:type => Thrift::Types::DOUBLE}, 'double')
88
+ @prot.write_type({:type => Thrift::Types::I16}, 'i16')
89
+ @prot.write_type({:type => Thrift::Types::I32}, 'i32')
90
+ @prot.write_type({:type => Thrift::Types::I64}, 'i64')
91
+ @prot.write_type({:type => Thrift::Types::STRING}, 'string')
92
+ @prot.write_type({:type => Thrift::Types::STRING, :binary => true}, 'binary')
93
+ @prot.write_type({:type => Thrift::Types::STRUCT}, struct)
94
+ # all other types are not implemented
95
+ [Thrift::Types::STOP, Thrift::Types::VOID, Thrift::Types::MAP, Thrift::Types::SET, Thrift::Types::LIST].each do |type|
96
+ expect { @prot.write_type({:type => type}, type.to_s) }.to raise_error(NotImplementedError)
97
+ end
98
+ end
99
+
100
+ it 'should read the different types (deprecated read_type signature)' do
101
+ @prot.should_receive(:read_bool).ordered
102
+ @prot.should_receive(:read_byte).ordered
103
+ @prot.should_receive(:read_i16).ordered
104
+ @prot.should_receive(:read_i32).ordered
105
+ @prot.should_receive(:read_i64).ordered
106
+ @prot.should_receive(:read_double).ordered
107
+ @prot.should_receive(:read_string).ordered
108
+ @prot.read_type(Thrift::Types::BOOL)
109
+ @prot.read_type(Thrift::Types::BYTE)
110
+ @prot.read_type(Thrift::Types::I16)
111
+ @prot.read_type(Thrift::Types::I32)
112
+ @prot.read_type(Thrift::Types::I64)
113
+ @prot.read_type(Thrift::Types::DOUBLE)
114
+ @prot.read_type(Thrift::Types::STRING)
115
+ # all other types are not implemented
116
+ [Thrift::Types::STOP, Thrift::Types::VOID, Thrift::Types::MAP,
117
+ Thrift::Types::SET, Thrift::Types::LIST, Thrift::Types::STRUCT].each do |type|
118
+ expect { @prot.read_type(type) }.to raise_error(NotImplementedError)
119
+ end
120
+ end
121
+
122
+ it 'should read the different types' do
123
+ @prot.should_receive(:read_bool).ordered
124
+ @prot.should_receive(:read_byte).ordered
125
+ @prot.should_receive(:read_i16).ordered
126
+ @prot.should_receive(:read_i32).ordered
127
+ @prot.should_receive(:read_i64).ordered
128
+ @prot.should_receive(:read_double).ordered
129
+ @prot.should_receive(:read_string).ordered
130
+ @prot.should_receive(:read_binary).ordered
131
+ @prot.read_type({:type => Thrift::Types::BOOL})
132
+ @prot.read_type({:type => Thrift::Types::BYTE})
133
+ @prot.read_type({:type => Thrift::Types::I16})
134
+ @prot.read_type({:type => Thrift::Types::I32})
135
+ @prot.read_type({:type => Thrift::Types::I64})
136
+ @prot.read_type({:type => Thrift::Types::DOUBLE})
137
+ @prot.read_type({:type => Thrift::Types::STRING})
138
+ @prot.read_type({:type => Thrift::Types::STRING, :binary => true})
139
+ # all other types are not implemented
140
+ [Thrift::Types::STOP, Thrift::Types::VOID, Thrift::Types::MAP,
141
+ Thrift::Types::SET, Thrift::Types::LIST, Thrift::Types::STRUCT].each do |type|
142
+ expect { @prot.read_type({:type => type}) }.to raise_error(NotImplementedError)
143
+ end
144
+ end
145
+
146
+ it "should skip the basic types" do
147
+ @prot.should_receive(:read_bool).ordered
148
+ @prot.should_receive(:read_byte).ordered
149
+ @prot.should_receive(:read_i16).ordered
150
+ @prot.should_receive(:read_i32).ordered
151
+ @prot.should_receive(:read_i64).ordered
152
+ @prot.should_receive(:read_double).ordered
153
+ @prot.should_receive(:read_string).ordered
154
+ @prot.skip(Thrift::Types::BOOL)
155
+ @prot.skip(Thrift::Types::BYTE)
156
+ @prot.skip(Thrift::Types::I16)
157
+ @prot.skip(Thrift::Types::I32)
158
+ @prot.skip(Thrift::Types::I64)
159
+ @prot.skip(Thrift::Types::DOUBLE)
160
+ @prot.skip(Thrift::Types::STRING)
161
+ @prot.skip(Thrift::Types::STOP) # should do absolutely nothing
162
+ end
163
+
164
+ it "should skip structs" do
165
+ real_skip = @prot.method(:skip)
166
+ @prot.should_receive(:read_struct_begin).ordered
167
+ @prot.should_receive(:read_field_begin).exactly(4).times.and_return(
168
+ ['field 1', Thrift::Types::STRING, 1],
169
+ ['field 2', Thrift::Types::I32, 2],
170
+ ['field 3', Thrift::Types::MAP, 3],
171
+ [nil, Thrift::Types::STOP, 0]
172
+ )
173
+ @prot.should_receive(:read_field_end).exactly(3).times
174
+ @prot.should_receive(:read_string).exactly(3).times
175
+ @prot.should_receive(:read_i32).ordered
176
+ @prot.should_receive(:read_map_begin).ordered.and_return([Thrift::Types::STRING, Thrift::Types::STRING, 1])
177
+ # @prot.should_receive(:read_string).exactly(2).times
178
+ @prot.should_receive(:read_map_end).ordered
179
+ @prot.should_receive(:read_struct_end).ordered
180
+ real_skip.call(Thrift::Types::STRUCT)
181
+ end
182
+
183
+ it "should skip maps" do
184
+ real_skip = @prot.method(:skip)
185
+ @prot.should_receive(:read_map_begin).ordered.and_return([Thrift::Types::STRING, Thrift::Types::STRUCT, 1])
186
+ @prot.should_receive(:read_string).ordered
187
+ @prot.should_receive(:read_struct_begin).ordered.and_return(["some_struct"])
188
+ @prot.should_receive(:read_field_begin).ordered.and_return([nil, Thrift::Types::STOP, nil]);
189
+ @prot.should_receive(:read_struct_end).ordered
190
+ @prot.should_receive(:read_map_end).ordered
191
+ real_skip.call(Thrift::Types::MAP)
192
+ end
193
+
194
+ it "should skip sets" do
195
+ real_skip = @prot.method(:skip)
196
+ @prot.should_receive(:read_set_begin).ordered.and_return([Thrift::Types::I64, 9])
197
+ @prot.should_receive(:read_i64).ordered.exactly(9).times
198
+ @prot.should_receive(:read_set_end)
199
+ real_skip.call(Thrift::Types::SET)
200
+ end
201
+
202
+ it "should skip lists" do
203
+ real_skip = @prot.method(:skip)
204
+ @prot.should_receive(:read_list_begin).ordered.and_return([Thrift::Types::DOUBLE, 11])
205
+ @prot.should_receive(:read_double).ordered.exactly(11).times
206
+ @prot.should_receive(:read_list_end)
207
+ real_skip.call(Thrift::Types::LIST)
208
+ end
209
+ end
210
+
211
+ describe Thrift::BaseProtocolFactory do
212
+ it "should raise NotImplementedError" do
213
+ # returning nil since Protocol is just an abstract class
214
+ lambda {Thrift::BaseProtocolFactory.new.get_protocol(mock("MockTransport"))}.should raise_error(NotImplementedError)
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,350 @@
1
+ #
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ #
19
+
20
+ require 'spec_helper'
21
+
22
+ describe 'BaseTransport' do
23
+
24
+ describe Thrift::TransportException do
25
+ it "should make type accessible" do
26
+ exc = Thrift::TransportException.new(Thrift::TransportException::ALREADY_OPEN, "msg")
27
+ exc.type.should == Thrift::TransportException::ALREADY_OPEN
28
+ exc.message.should == "msg"
29
+ end
30
+ end
31
+
32
+ describe Thrift::BaseTransport do
33
+ it "should read the specified size" do
34
+ transport = Thrift::BaseTransport.new
35
+ transport.should_receive(:read).with(40).ordered.and_return("10 letters")
36
+ transport.should_receive(:read).with(30).ordered.and_return("fifteen letters")
37
+ transport.should_receive(:read).with(15).ordered.and_return("more characters")
38
+ transport.read_all(40).should == "10 lettersfifteen lettersmore characters"
39
+ end
40
+
41
+ it "should stub out the rest of the methods" do
42
+ # can't test for stubbiness, so just make sure they're defined
43
+ [:open?, :open, :close, :read, :write, :flush].each do |sym|
44
+ Thrift::BaseTransport.method_defined?(sym).should be_true
45
+ end
46
+ end
47
+
48
+ it "should alias << to write" do
49
+ Thrift::BaseTransport.instance_method(:<<).should == Thrift::BaseTransport.instance_method(:write)
50
+ end
51
+ end
52
+
53
+ describe Thrift::BaseServerTransport do
54
+ it "should stub out its methods" do
55
+ [:listen, :accept, :close].each do |sym|
56
+ Thrift::BaseServerTransport.method_defined?(sym).should be_true
57
+ end
58
+ end
59
+ end
60
+
61
+ describe Thrift::BaseTransportFactory do
62
+ it "should return the transport it's given" do
63
+ transport = mock("Transport")
64
+ Thrift::BaseTransportFactory.new.get_transport(transport).should eql(transport)
65
+ end
66
+ end
67
+
68
+ describe Thrift::BufferedTransport do
69
+ it "should pass through everything but write/flush/read" do
70
+ trans = mock("Transport")
71
+ trans.should_receive(:open?).ordered.and_return("+ open?")
72
+ trans.should_receive(:open).ordered.and_return("+ open")
73
+ trans.should_receive(:flush).ordered # from the close
74
+ trans.should_receive(:close).ordered.and_return("+ close")
75
+ btrans = Thrift::BufferedTransport.new(trans)
76
+ btrans.open?.should == "+ open?"
77
+ btrans.open.should == "+ open"
78
+ btrans.close.should == "+ close"
79
+ end
80
+
81
+ it "should buffer reads in chunks of #{Thrift::BufferedTransport::DEFAULT_BUFFER}" do
82
+ trans = mock("Transport")
83
+ trans.should_receive(:read).with(Thrift::BufferedTransport::DEFAULT_BUFFER).and_return("lorum ipsum dolor emet")
84
+ btrans = Thrift::BufferedTransport.new(trans)
85
+ btrans.read(6).should == "lorum "
86
+ btrans.read(6).should == "ipsum "
87
+ btrans.read(6).should == "dolor "
88
+ btrans.read(6).should == "emet"
89
+ end
90
+
91
+ it "should buffer writes and send them on flush" do
92
+ trans = mock("Transport")
93
+ btrans = Thrift::BufferedTransport.new(trans)
94
+ btrans.write("one/")
95
+ btrans.write("two/")
96
+ btrans.write("three/")
97
+ trans.should_receive(:write).with("one/two/three/").ordered
98
+ trans.should_receive(:flush).ordered
99
+ btrans.flush
100
+ end
101
+
102
+ it "should only send buffered data once" do
103
+ trans = mock("Transport")
104
+ btrans = Thrift::BufferedTransport.new(trans)
105
+ btrans.write("one/")
106
+ btrans.write("two/")
107
+ btrans.write("three/")
108
+ trans.should_receive(:write).with("one/two/three/")
109
+ trans.stub!(:flush)
110
+ btrans.flush
111
+ # Nothing to flush with no data
112
+ btrans.flush
113
+ end
114
+
115
+ it "should flush on close" do
116
+ trans = mock("Transport")
117
+ trans.should_receive(:close)
118
+ btrans = Thrift::BufferedTransport.new(trans)
119
+ btrans.should_receive(:flush)
120
+ btrans.close
121
+ end
122
+
123
+ it "should not write to socket if there's no data" do
124
+ trans = mock("Transport")
125
+ trans.should_receive(:flush)
126
+ btrans = Thrift::BufferedTransport.new(trans)
127
+ btrans.flush
128
+ end
129
+ end
130
+
131
+ describe Thrift::BufferedTransportFactory do
132
+ it "should wrap the given transport in a BufferedTransport" do
133
+ trans = mock("Transport")
134
+ btrans = mock("BufferedTransport")
135
+ Thrift::BufferedTransport.should_receive(:new).with(trans).and_return(btrans)
136
+ Thrift::BufferedTransportFactory.new.get_transport(trans).should == btrans
137
+ end
138
+ end
139
+
140
+ describe Thrift::FramedTransport do
141
+ before(:each) do
142
+ @trans = mock("Transport")
143
+ end
144
+
145
+ it "should pass through open?/open/close" do
146
+ ftrans = Thrift::FramedTransport.new(@trans)
147
+ @trans.should_receive(:open?).ordered.and_return("+ open?")
148
+ @trans.should_receive(:open).ordered.and_return("+ open")
149
+ @trans.should_receive(:close).ordered.and_return("+ close")
150
+ ftrans.open?.should == "+ open?"
151
+ ftrans.open.should == "+ open"
152
+ ftrans.close.should == "+ close"
153
+ end
154
+
155
+ it "should pass through read when read is turned off" do
156
+ ftrans = Thrift::FramedTransport.new(@trans, false, true)
157
+ @trans.should_receive(:read).with(17).ordered.and_return("+ read")
158
+ ftrans.read(17).should == "+ read"
159
+ end
160
+
161
+ it "should pass through write/flush when write is turned off" do
162
+ ftrans = Thrift::FramedTransport.new(@trans, true, false)
163
+ @trans.should_receive(:write).with("foo").ordered.and_return("+ write")
164
+ @trans.should_receive(:flush).ordered.and_return("+ flush")
165
+ ftrans.write("foo").should == "+ write"
166
+ ftrans.flush.should == "+ flush"
167
+ end
168
+
169
+ it "should return a full frame if asked for >= the frame's length" do
170
+ frame = "this is a frame"
171
+ @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
172
+ @trans.should_receive(:read_all).with(frame.length).and_return(frame)
173
+ Thrift::FramedTransport.new(@trans).read(frame.length + 10).should == frame
174
+ end
175
+
176
+ it "should return slices of the frame when asked for < the frame's length" do
177
+ frame = "this is a frame"
178
+ @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017")
179
+ @trans.should_receive(:read_all).with(frame.length).and_return(frame)
180
+ ftrans = Thrift::FramedTransport.new(@trans)
181
+ ftrans.read(4).should == "this"
182
+ ftrans.read(4).should == " is "
183
+ ftrans.read(16).should == "a frame"
184
+ end
185
+
186
+ it "should return nothing if asked for <= 0" do
187
+ Thrift::FramedTransport.new(@trans).read(-2).should == ""
188
+ end
189
+
190
+ it "should pull a new frame when the first is exhausted" do
191
+ frame = "this is a frame"
192
+ frame2 = "yet another frame"
193
+ @trans.should_receive(:read_all).with(4).and_return("\000\000\000\017", "\000\000\000\021")
194
+ @trans.should_receive(:read_all).with(frame.length).and_return(frame)
195
+ @trans.should_receive(:read_all).with(frame2.length).and_return(frame2)
196
+ ftrans = Thrift::FramedTransport.new(@trans)
197
+ ftrans.read(4).should == "this"
198
+ ftrans.read(8).should == " is a fr"
199
+ ftrans.read(6).should == "ame"
200
+ ftrans.read(4).should == "yet "
201
+ ftrans.read(16).should == "another frame"
202
+ end
203
+
204
+ it "should buffer writes" do
205
+ ftrans = Thrift::FramedTransport.new(@trans)
206
+ @trans.should_not_receive(:write)
207
+ ftrans.write("foo")
208
+ ftrans.write("bar")
209
+ ftrans.write("this is a frame")
210
+ end
211
+
212
+ it "should write slices of the buffer" do
213
+ ftrans = Thrift::FramedTransport.new(@trans)
214
+ ftrans.write("foobar", 3)
215
+ ftrans.write("barfoo", 1)
216
+ @trans.stub!(:flush)
217
+ @trans.should_receive(:write).with("\000\000\000\004foob")
218
+ ftrans.flush
219
+ end
220
+
221
+ it "should flush frames with a 4-byte header" do
222
+ ftrans = Thrift::FramedTransport.new(@trans)
223
+ @trans.should_receive(:write).with("\000\000\000\035one/two/three/this is a frame").ordered
224
+ @trans.should_receive(:flush).ordered
225
+ ftrans.write("one/")
226
+ ftrans.write("two/")
227
+ ftrans.write("three/")
228
+ ftrans.write("this is a frame")
229
+ ftrans.flush
230
+ end
231
+
232
+ it "should not flush the same buffered data twice" do
233
+ ftrans = Thrift::FramedTransport.new(@trans)
234
+ @trans.should_receive(:write).with("\000\000\000\007foo/bar")
235
+ @trans.stub!(:flush)
236
+ ftrans.write("foo")
237
+ ftrans.write("/bar")
238
+ ftrans.flush
239
+ @trans.should_receive(:write).with("\000\000\000\000")
240
+ ftrans.flush
241
+ end
242
+ end
243
+
244
+ describe Thrift::FramedTransportFactory do
245
+ it "should wrap the given transport in a FramedTransport" do
246
+ trans = mock("Transport")
247
+ Thrift::FramedTransport.should_receive(:new).with(trans)
248
+ Thrift::FramedTransportFactory.new.get_transport(trans)
249
+ end
250
+ end
251
+
252
+ describe Thrift::MemoryBufferTransport do
253
+ before(:each) do
254
+ @buffer = Thrift::MemoryBufferTransport.new
255
+ end
256
+
257
+ it "should accept a buffer on input and use it directly" do
258
+ s = "this is a test"
259
+ @buffer = Thrift::MemoryBufferTransport.new(s)
260
+ @buffer.read(4).should == "this"
261
+ s.slice!(-4..-1)
262
+ @buffer.read(@buffer.available).should == " is a "
263
+ end
264
+
265
+ it "should always remain open" do
266
+ @buffer.should be_open
267
+ @buffer.close
268
+ @buffer.should be_open
269
+ end
270
+
271
+ it "should respond to peek and available" do
272
+ @buffer.write "some data"
273
+ @buffer.peek.should be_true
274
+ @buffer.available.should == 9
275
+ @buffer.read(4)
276
+ @buffer.peek.should be_true
277
+ @buffer.available.should == 5
278
+ @buffer.read(5)
279
+ @buffer.peek.should be_false
280
+ @buffer.available.should == 0
281
+ end
282
+
283
+ it "should be able to reset the buffer" do
284
+ @buffer.write "test data"
285
+ @buffer.reset_buffer("foobar")
286
+ @buffer.available.should == 6
287
+ @buffer.read(@buffer.available).should == "foobar"
288
+ @buffer.reset_buffer
289
+ @buffer.available.should == 0
290
+ end
291
+
292
+ it "should copy the given string when resetting the buffer" do
293
+ s = "this is a test"
294
+ @buffer.reset_buffer(s)
295
+ @buffer.available.should == 14
296
+ @buffer.read(10)
297
+ @buffer.available.should == 4
298
+ s.should == "this is a test"
299
+ end
300
+
301
+ it "should return from read what was given in write" do
302
+ @buffer.write "test data"
303
+ @buffer.read(4).should == "test"
304
+ @buffer.read(@buffer.available).should == " data"
305
+ @buffer.write "foo"
306
+ @buffer.write " bar"
307
+ @buffer.read(@buffer.available).should == "foo bar"
308
+ end
309
+
310
+ it "should throw an EOFError when there isn't enough data in the buffer" do
311
+ @buffer.reset_buffer("")
312
+ lambda{@buffer.read(1)}.should raise_error(EOFError)
313
+
314
+ @buffer.reset_buffer("1234")
315
+ lambda{@buffer.read(5)}.should raise_error(EOFError)
316
+ end
317
+ end
318
+
319
+ describe Thrift::IOStreamTransport do
320
+ before(:each) do
321
+ @input = mock("Input", :closed? => false)
322
+ @output = mock("Output", :closed? => false)
323
+ @trans = Thrift::IOStreamTransport.new(@input, @output)
324
+ end
325
+
326
+ it "should be open as long as both input or output are open" do
327
+ @trans.should be_open
328
+ @input.stub!(:closed?).and_return(true)
329
+ @trans.should be_open
330
+ @input.stub!(:closed?).and_return(false)
331
+ @output.stub!(:closed?).and_return(true)
332
+ @trans.should be_open
333
+ @input.stub!(:closed?).and_return(true)
334
+ @trans.should_not be_open
335
+ end
336
+
337
+ it "should pass through read/write to input/output" do
338
+ @input.should_receive(:read).with(17).and_return("+ read")
339
+ @output.should_receive(:write).with("foobar").and_return("+ write")
340
+ @trans.read(17).should == "+ read"
341
+ @trans.write("foobar").should == "+ write"
342
+ end
343
+
344
+ it "should close both input and output when closed" do
345
+ @input.should_receive(:close)
346
+ @output.should_receive(:close)
347
+ @trans.close
348
+ end
349
+ end
350
+ end