thrift 0.22.0 → 0.24.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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +235 -17
  3. data/benchmark/benchmark.rb +23 -8
  4. data/benchmark/client.rb +50 -6
  5. data/benchmark/server.rb +46 -7
  6. data/benchmark/thin_server.rb +2 -0
  7. data/ext/binary_protocol_accelerated.c +154 -42
  8. data/ext/bytes.c +14 -0
  9. data/ext/compact_protocol.c +138 -45
  10. data/ext/constants.h +12 -0
  11. data/ext/extconf.rb +17 -8
  12. data/ext/memory_buffer.c +44 -7
  13. data/ext/protocol.c +29 -0
  14. data/ext/protocol.h +35 -0
  15. data/ext/struct.c +48 -17
  16. data/ext/thrift_native.c +28 -3
  17. data/lib/thrift/bytes.rb +70 -100
  18. data/lib/thrift/client.rb +54 -13
  19. data/lib/thrift/exceptions.rb +6 -5
  20. data/lib/thrift/multiplexed_processor.rb +20 -10
  21. data/lib/thrift/processor.rb +7 -6
  22. data/lib/thrift/protocol/base_protocol.rb +52 -21
  23. data/lib/thrift/protocol/binary_protocol.rb +65 -20
  24. data/lib/thrift/protocol/binary_protocol_accelerated.rb +6 -5
  25. data/lib/thrift/protocol/compact_protocol.rb +76 -41
  26. data/lib/thrift/protocol/header_protocol.rb +321 -0
  27. data/lib/thrift/protocol/json_protocol.rb +44 -27
  28. data/lib/thrift/protocol/multiplexed_protocol.rb +6 -5
  29. data/lib/thrift/protocol/protocol_decorator.rb +13 -4
  30. data/lib/thrift/serializer/deserializer.rb +6 -5
  31. data/lib/thrift/serializer/serializer.rb +5 -5
  32. data/lib/thrift/server/base_server.rb +5 -4
  33. data/lib/thrift/server/mongrel_http_server.rb +7 -6
  34. data/lib/thrift/server/nonblocking_server.rb +35 -9
  35. data/lib/thrift/server/simple_server.rb +13 -5
  36. data/lib/thrift/server/thin_http_server.rb +4 -3
  37. data/lib/thrift/server/thread_pool_server.rb +7 -6
  38. data/lib/thrift/server/threaded_server.rb +13 -5
  39. data/lib/thrift/struct.rb +12 -11
  40. data/lib/thrift/struct_union.rb +14 -9
  41. data/lib/thrift/thrift_native.rb +3 -2
  42. data/lib/thrift/transport/base_server_transport.rb +8 -5
  43. data/lib/thrift/transport/base_transport.rb +18 -14
  44. data/lib/thrift/transport/buffered_transport.rb +7 -6
  45. data/lib/thrift/transport/framed_transport.rb +8 -7
  46. data/lib/thrift/transport/header_transport.rb +562 -0
  47. data/lib/thrift/transport/http_client_transport.rb +2 -1
  48. data/lib/thrift/transport/io_stream_transport.rb +4 -3
  49. data/lib/thrift/transport/memory_buffer_transport.rb +13 -6
  50. data/lib/thrift/transport/server_socket.rb +14 -8
  51. data/lib/thrift/transport/socket.rb +126 -60
  52. data/lib/thrift/transport/ssl_server_socket.rb +4 -3
  53. data/lib/thrift/transport/ssl_socket.rb +45 -13
  54. data/lib/thrift/transport/unix_server_socket.rb +9 -5
  55. data/lib/thrift/transport/unix_socket.rb +7 -6
  56. data/lib/thrift/types.rb +10 -6
  57. data/lib/thrift/union.rb +15 -8
  58. data/lib/thrift/uuid.rb +50 -0
  59. data/lib/thrift.rb +4 -1
  60. data/spec/ThriftSpec.thrift +21 -1
  61. data/spec/base_protocol_spec.rb +21 -2
  62. data/spec/base_transport_spec.rb +48 -8
  63. data/spec/binary_protocol_accelerated_spec.rb +1 -0
  64. data/spec/binary_protocol_spec.rb +1 -2
  65. data/spec/binary_protocol_spec_shared.rb +206 -155
  66. data/spec/bytes_spec.rb +71 -114
  67. data/spec/client_spec.rb +86 -19
  68. data/spec/compact_protocol_spec.rb +153 -16
  69. data/spec/constants_demo_spec.rb +102 -0
  70. data/spec/exception_spec.rb +1 -1
  71. data/spec/flat_spec.rb +1 -0
  72. data/spec/header_protocol_spec.rb +476 -0
  73. data/spec/header_transport_spec.rb +431 -0
  74. data/spec/http_client_spec.rb +5 -6
  75. data/spec/json_protocol_spec.rb +69 -47
  76. data/spec/multiplexed_processor_spec.rb +75 -0
  77. data/spec/namespaced_spec.rb +1 -1
  78. data/spec/nonblocking_server_spec.rb +174 -8
  79. data/spec/processor_spec.rb +1 -1
  80. data/spec/recursion_depth_spec.rb +223 -0
  81. data/spec/serializer_spec.rb +1 -1
  82. data/spec/server_socket_spec.rb +38 -1
  83. data/spec/server_spec.rb +60 -9
  84. data/spec/socket_spec.rb +119 -13
  85. data/spec/socket_spec_shared.rb +73 -9
  86. data/spec/spec_helper.rb +2 -1
  87. data/spec/ssl_server_socket_spec.rb +52 -1
  88. data/spec/ssl_socket_spec.rb +181 -11
  89. data/spec/struct_nested_containers_spec.rb +2 -2
  90. data/spec/struct_spec.rb +114 -9
  91. data/spec/support/header_protocol_helper.rb +55 -0
  92. data/spec/thin_http_server_spec.rb +4 -18
  93. data/spec/types_spec.rb +26 -26
  94. data/spec/union_spec.rb +70 -11
  95. data/spec/unix_socket_spec.rb +17 -2
  96. data/spec/uuid_validation_spec.rb +239 -0
  97. data/test/fuzz/Makefile +779 -0
  98. data/test/fuzz/Makefile.am +173 -0
  99. data/test/fuzz/Makefile.in +775 -0
  100. data/test/fuzz/README.md +149 -0
  101. data/test/fuzz/fuzz_common.rb +96 -0
  102. data/{lib/thrift/core_ext.rb → test/fuzz/fuzz_parse_binary_protocol.rb} +4 -4
  103. data/{lib/thrift/core_ext/fixnum.rb → test/fuzz/fuzz_parse_binary_protocol_accelerated.rb} +7 -13
  104. data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +23 -0
  105. data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +23 -0
  106. data/test/fuzz/fuzz_parse_compact_protocol.rb +23 -0
  107. data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +23 -0
  108. data/test/fuzz/fuzz_parse_json_protocol.rb +23 -0
  109. data/test/fuzz/fuzz_parse_json_protocol_harness.rb +23 -0
  110. data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +23 -0
  111. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +23 -0
  112. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +23 -0
  113. data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +23 -0
  114. data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +23 -0
  115. data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +23 -0
  116. data/test/fuzz/fuzz_roundtrip_json_protocol.rb +23 -0
  117. data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +23 -0
  118. data/test/fuzz/fuzz_tracer.rb +29 -0
  119. metadata +105 -70
@@ -0,0 +1,102 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+ #
4
+ # Licensed to the Apache Software Foundation (ASF) under one
5
+ # or more contributor license agreements. See the NOTICE file
6
+ # distributed with this work for additional information
7
+ # regarding copyright ownership. The ASF licenses this file
8
+ # to you under the Apache License, Version 2.0 (the
9
+ # "License"); you may not use this file except in compliance
10
+ # with the License. You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing,
15
+ # software distributed under the License is distributed on an
16
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17
+ # KIND, either express or implied. See the License for the
18
+ # specific language governing permissions and limitations
19
+ # under the License.
20
+ #
21
+
22
+ require 'spec_helper'
23
+
24
+ $:.unshift File.join(File.dirname(__FILE__), *%w[gen-rb/constants_demo])
25
+ require 'constants_demo_constants'
26
+
27
+ describe 'ConstantsDemo' do
28
+ it 'should have correct integer constants' do
29
+ expect(ConstantsDemo::MyInt).to eq(3)
30
+ expect(ConstantsDemo::Hex_const).to eq(0x0001F)
31
+ expect(ConstantsDemo::Negative_hex_constant).to eq(-0x0001F)
32
+ expect(ConstantsDemo::GEN_ME).to eq(-3523553)
33
+ end
34
+
35
+ it 'should have correct double constants' do
36
+ expect(ConstantsDemo::GEn_DUB).to eq(325.532)
37
+ expect(ConstantsDemo::GEn_DU).to eq(85.2355)
38
+ expect(ConstantsDemo::E10).to eq(1e+10)
39
+ expect(ConstantsDemo::E11).to eq(-1e+10)
40
+ end
41
+
42
+ it 'should have correct string constants' do
43
+ expect(ConstantsDemo::GEN_STRING).to eq("asldkjasfd")
44
+ end
45
+
46
+ it 'should have correct uuid constants' do
47
+ expect(ConstantsDemo::GEN_UUID).to eq("00000000-4444-CCCC-ffff-0123456789ab")
48
+ expect(ConstantsDemo::GEN_GUID).to eq("00112233-4455-6677-8899-aaBBccDDeeFF")
49
+ expect(ConstantsDemo::MY_UUID).to eq("00000000-4444-CCCC-ffff-0123456789ab")
50
+ expect(ConstantsDemo::MY_GUID).to eq("00112233-4455-6677-8899-aaBBccDDeeFF")
51
+ end
52
+
53
+ it 'should have correct list constants' do
54
+ expect(ConstantsDemo::GEN_LIST).to be_a(Array)
55
+ expect(ConstantsDemo::GEN_LIST).to eq([235235, 23598352, 3253523])
56
+ end
57
+
58
+ it 'should have correct map constants' do
59
+ expect(ConstantsDemo::GEN_MAP).to be_a(Hash)
60
+ expect(ConstantsDemo::GEN_MAP[35532]).to eq(233)
61
+ expect(ConstantsDemo::GEN_MAP[43523]).to eq(853)
62
+
63
+ expect(ConstantsDemo::GEN_MAP2).to be_a(Hash)
64
+ expect(ConstantsDemo::GEN_MAP2["hello"]).to eq(233)
65
+ expect(ConstantsDemo::GEN_MAP2["lkj98d"]).to eq(853)
66
+ expect(ConstantsDemo::GEN_MAP2['lkjsdf']).to eq(98325)
67
+
68
+ expect(ConstantsDemo::GEN_MAPMAP).to be_a(Hash)
69
+ expect(ConstantsDemo::GEN_MAPMAP[235]).to be_a(Hash)
70
+ expect(ConstantsDemo::GEN_MAPMAP[235][532]).to eq(53255)
71
+ expect(ConstantsDemo::GEN_MAPMAP[235][235]).to eq(235)
72
+ end
73
+
74
+ it 'should have correct set constants' do
75
+ expect(ConstantsDemo::GEN_SET).to be_a(Set)
76
+ expect(ConstantsDemo::GEN_SET.size).to eq(2)
77
+ expect(ConstantsDemo::GEN_SET.include?(235)).to be true # added twice, but this is a set
78
+ expect(ConstantsDemo::GEN_SET.include?(53235)).to be true
79
+
80
+ expect(ConstantsDemo::GUID_SET).to be_a(Set)
81
+ expect(ConstantsDemo::GUID_SET.size).to eq(2)
82
+ expect(ConstantsDemo::GUID_SET.include?("00112233-4455-6677-8899-aaBBccDDeeFF")).to be true
83
+ expect(ConstantsDemo::GUID_SET.include?("00000000-4444-CCCC-ffff-0123456789ab")).to be true
84
+ end
85
+
86
+ it 'should have correct struct constants' do
87
+ expect(ConstantsDemo::GEN_THING).to be_a(Thrift::Struct)
88
+ expect(ConstantsDemo::GEN_THING.hello).to eq(325)
89
+ expect(ConstantsDemo::GEN_THING.goodbye).to eq(325352)
90
+ expect(ConstantsDemo::GEN_THING.id).to eq("00112233-4455-6677-8899-aaBBccDDeeFF")
91
+ expect(ConstantsDemo::GEN_THING.my_id).to eq("00000000-4444-CCCC-ffff-0123456789ab")
92
+ expect(ConstantsDemo::GEN_THING.my_optional_id).to eq("00000000-4444-CCCC-ffff-0123456789ab")
93
+
94
+ expect(ConstantsDemo::GEN_WHAT).to be_a(Hash)
95
+ expect(ConstantsDemo::GEN_WHAT[35]).to be_a(Thrift::Struct)
96
+ expect(ConstantsDemo::GEN_WHAT[35].hello).to eq(325)
97
+ expect(ConstantsDemo::GEN_WHAT[35].goodbye).to eq(325352)
98
+ expect(ConstantsDemo::GEN_WHAT[35].id).to eq("00000000-4444-CCCC-ffff-0123456789ab")
99
+ expect(ConstantsDemo::GEN_WHAT[35].my_id).to eq("00000000-4444-CCCC-ffff-0123456789ab")
100
+ expect(ConstantsDemo::GEN_WHAT[35].my_optional_id).to eq("00000000-4444-CCCC-ffff-0123456789ab")
101
+ end
102
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # Licensed to the Apache Software Foundation (ASF) under one
3
4
  # or more contributor license agreements. See the NOTICE file
@@ -20,7 +21,6 @@
20
21
  require 'spec_helper'
21
22
 
22
23
  describe 'Exception' do
23
-
24
24
  describe Thrift::Exception do
25
25
  it "should have an accessible message" do
26
26
  e = Thrift::Exception.new("test message")
data/spec/flat_spec.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  #
2
3
  # Licensed to the Apache Software Foundation (ASF) under one
3
4
  # or more contributor license agreements. See the NOTICE file
@@ -0,0 +1,476 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+
21
+ require 'spec_helper'
22
+ require_relative 'support/header_protocol_helper'
23
+
24
+ describe 'HeaderProtocol' do
25
+ include HeaderProtocolHelper
26
+
27
+ describe Thrift::HeaderProtocol do
28
+ before(:each) do
29
+ @buffer = Thrift::MemoryBufferTransport.new
30
+ @protocol = Thrift::HeaderProtocol.new(@buffer)
31
+ end
32
+
33
+ it "should provide a to_s" do
34
+ expect(@protocol.to_s).to match(/header\(compact/)
35
+ end
36
+
37
+ it "should wrap transport in HeaderTransport" do
38
+ expect(@protocol.trans).to be_a(Thrift::HeaderTransport)
39
+ end
40
+
41
+ it "should use existing HeaderTransport if passed" do
42
+ header_trans = Thrift::HeaderTransport.new(@buffer)
43
+ protocol = Thrift::HeaderProtocol.new(header_trans)
44
+ expect(protocol.trans).to equal(header_trans)
45
+ end
46
+
47
+ describe "header management delegation" do
48
+ it "should delegate get_headers" do
49
+ # Write with headers and read back to populate read headers
50
+ @protocol.set_header("key", "value")
51
+ @protocol.write_message_begin("test", Thrift::MessageTypes::CALL, 1)
52
+ @protocol.write_struct_begin("args")
53
+ @protocol.write_field_stop
54
+ @protocol.write_struct_end
55
+ @protocol.write_message_end
56
+ @protocol.trans.flush
57
+
58
+ # Read back
59
+ data = @buffer.read(@buffer.available)
60
+ read_buffer = Thrift::MemoryBufferTransport.new(data)
61
+ read_protocol = Thrift::HeaderProtocol.new(read_buffer)
62
+
63
+ read_protocol.read_message_begin
64
+ headers = read_protocol.get_headers
65
+ expect(headers["key"]).to eq("value")
66
+ end
67
+
68
+ it "should delegate set_header" do
69
+ expect(@protocol.trans).to receive(:set_header).with("key", "value")
70
+ @protocol.set_header("key", "value")
71
+ end
72
+
73
+ it "should delegate clear_headers" do
74
+ expect(@protocol.trans).to receive(:clear_headers)
75
+ @protocol.clear_headers
76
+ end
77
+
78
+ it "should delegate add_transform" do
79
+ expect(@protocol.trans).to receive(:add_transform).with(Thrift::HeaderTransformID::ZLIB)
80
+ @protocol.add_transform(Thrift::HeaderTransformID::ZLIB)
81
+ end
82
+ end
83
+
84
+ describe "protocol delegation with Binary protocol" do
85
+ before(:each) do
86
+ @buffer = Thrift::MemoryBufferTransport.new
87
+ @protocol = Thrift::HeaderProtocol.new(@buffer, nil, Thrift::HeaderSubprotocolID::BINARY)
88
+ end
89
+
90
+ it "should write message begin" do
91
+ @protocol.write_message_begin("test_method", Thrift::MessageTypes::CALL, 123)
92
+ @protocol.write_message_end
93
+ @protocol.trans.flush
94
+
95
+ # Verify we can read it back
96
+ data = @buffer.read(@buffer.available)
97
+ read_buffer = Thrift::MemoryBufferTransport.new(data)
98
+ read_protocol = Thrift::HeaderProtocol.new(read_buffer)
99
+
100
+ name, type, seqid = read_protocol.read_message_begin
101
+ expect(name).to eq("test_method")
102
+ expect(type).to eq(Thrift::MessageTypes::CALL)
103
+ expect(seqid).to eq(123)
104
+ end
105
+
106
+ it "should propagate seqid to the outer header frame" do
107
+ @protocol.write_message_begin("test_method", Thrift::MessageTypes::CALL, 123)
108
+ @protocol.write_message_end
109
+ @protocol.trans.flush
110
+
111
+ data = @buffer.read(@buffer.available)
112
+ expect(data[8, 4].unpack('N').first).to eq(123)
113
+ end
114
+
115
+ it "should write and read structs" do
116
+ @protocol.write_message_begin("test", Thrift::MessageTypes::CALL, 1)
117
+ @protocol.write_struct_begin("TestStruct")
118
+ @protocol.write_field_begin("field1", Thrift::Types::I32, 1)
119
+ @protocol.write_i32(42)
120
+ @protocol.write_field_end
121
+ @protocol.write_field_stop
122
+ @protocol.write_struct_end
123
+ @protocol.write_message_end
124
+ @protocol.trans.flush
125
+
126
+ data = @buffer.read(@buffer.available)
127
+ read_buffer = Thrift::MemoryBufferTransport.new(data)
128
+ read_protocol = Thrift::HeaderProtocol.new(read_buffer)
129
+
130
+ read_protocol.read_message_begin
131
+ read_protocol.read_struct_begin
132
+ name, type, id = read_protocol.read_field_begin
133
+ expect(type).to eq(Thrift::Types::I32)
134
+ expect(id).to eq(1)
135
+ value = read_protocol.read_i32
136
+ expect(value).to eq(42)
137
+ end
138
+
139
+ it "should write and read all primitive types" do
140
+ @protocol.write_message_begin("test", Thrift::MessageTypes::CALL, 1)
141
+ @protocol.write_struct_begin("TestStruct")
142
+
143
+ @protocol.write_field_begin("bool", Thrift::Types::BOOL, 1)
144
+ @protocol.write_bool(true)
145
+ @protocol.write_field_end
146
+
147
+ @protocol.write_field_begin("byte", Thrift::Types::BYTE, 2)
148
+ @protocol.write_byte(127)
149
+ @protocol.write_field_end
150
+
151
+ @protocol.write_field_begin("i16", Thrift::Types::I16, 3)
152
+ @protocol.write_i16(32767)
153
+ @protocol.write_field_end
154
+
155
+ @protocol.write_field_begin("i32", Thrift::Types::I32, 4)
156
+ @protocol.write_i32(2147483647)
157
+ @protocol.write_field_end
158
+
159
+ @protocol.write_field_begin("i64", Thrift::Types::I64, 5)
160
+ @protocol.write_i64(9223372036854775807)
161
+ @protocol.write_field_end
162
+
163
+ @protocol.write_field_begin("double", Thrift::Types::DOUBLE, 6)
164
+ @protocol.write_double(3.14159)
165
+ @protocol.write_field_end
166
+
167
+ @protocol.write_field_begin("string", Thrift::Types::STRING, 7)
168
+ @protocol.write_string("hello")
169
+ @protocol.write_field_end
170
+
171
+ @protocol.write_field_stop
172
+ @protocol.write_struct_end
173
+ @protocol.write_message_end
174
+ @protocol.trans.flush
175
+
176
+ data = @buffer.read(@buffer.available)
177
+ read_buffer = Thrift::MemoryBufferTransport.new(data)
178
+ read_protocol = Thrift::HeaderProtocol.new(read_buffer)
179
+
180
+ read_protocol.read_message_begin
181
+ read_protocol.read_struct_begin
182
+
183
+ # bool
184
+ _, type, _ = read_protocol.read_field_begin
185
+ expect(type).to eq(Thrift::Types::BOOL)
186
+ expect(read_protocol.read_bool).to eq(true)
187
+ read_protocol.read_field_end
188
+
189
+ # byte
190
+ _, type, _ = read_protocol.read_field_begin
191
+ expect(type).to eq(Thrift::Types::BYTE)
192
+ expect(read_protocol.read_byte).to eq(127)
193
+ read_protocol.read_field_end
194
+
195
+ # i16
196
+ _, type, _ = read_protocol.read_field_begin
197
+ expect(type).to eq(Thrift::Types::I16)
198
+ expect(read_protocol.read_i16).to eq(32767)
199
+ read_protocol.read_field_end
200
+
201
+ # i32
202
+ _, type, _ = read_protocol.read_field_begin
203
+ expect(type).to eq(Thrift::Types::I32)
204
+ expect(read_protocol.read_i32).to eq(2147483647)
205
+ read_protocol.read_field_end
206
+
207
+ # i64
208
+ _, type, _ = read_protocol.read_field_begin
209
+ expect(type).to eq(Thrift::Types::I64)
210
+ expect(read_protocol.read_i64).to eq(9223372036854775807)
211
+ read_protocol.read_field_end
212
+
213
+ # double
214
+ _, type, _ = read_protocol.read_field_begin
215
+ expect(type).to eq(Thrift::Types::DOUBLE)
216
+ expect(read_protocol.read_double).to be_within(0.00001).of(3.14159)
217
+ read_protocol.read_field_end
218
+
219
+ # string
220
+ _, type, _ = read_protocol.read_field_begin
221
+ expect(type).to eq(Thrift::Types::STRING)
222
+ expect(read_protocol.read_string).to eq("hello")
223
+ read_protocol.read_field_end
224
+ end
225
+ end
226
+
227
+ describe "protocol delegation with Compact protocol" do
228
+ before(:each) do
229
+ @buffer = Thrift::MemoryBufferTransport.new
230
+ @protocol = Thrift::HeaderProtocol.new(
231
+ @buffer,
232
+ nil,
233
+ Thrift::HeaderSubprotocolID::COMPACT
234
+ )
235
+ end
236
+
237
+ it "should use Compact protocol" do
238
+ expect(@protocol.to_s).to match(/header\(compact/)
239
+ end
240
+
241
+ it "should write and read with Compact protocol" do
242
+ @protocol.write_message_begin("test", Thrift::MessageTypes::CALL, 1)
243
+ @protocol.write_struct_begin("Test")
244
+ @protocol.write_field_begin("field", Thrift::Types::I32, 1)
245
+ @protocol.write_i32(999)
246
+ @protocol.write_field_end
247
+ @protocol.write_field_stop
248
+ @protocol.write_struct_end
249
+ @protocol.write_message_end
250
+ @protocol.trans.flush
251
+
252
+ data = @buffer.read(@buffer.available)
253
+ read_buffer = Thrift::MemoryBufferTransport.new(data)
254
+ read_protocol = Thrift::HeaderProtocol.new(read_buffer, nil, Thrift::HeaderSubprotocolID::COMPACT)
255
+
256
+ read_protocol.read_message_begin
257
+ read_protocol.read_struct_begin
258
+ _, type, _ = read_protocol.read_field_begin
259
+ expect(type).to eq(Thrift::Types::I32)
260
+ expect(read_protocol.read_i32).to eq(999)
261
+ end
262
+ end
263
+
264
+ describe "unknown protocol handling" do
265
+ it "should write an exception response on unknown protocol id" do
266
+ header_data = +""
267
+ header_data << varint32(0x10)
268
+ header_data << varint32(0)
269
+ frame = build_header_frame(header_data)
270
+
271
+ buffer = Thrift::MemoryBufferTransport.new(frame)
272
+ protocol = Thrift::HeaderProtocol.new(buffer)
273
+
274
+ expect { protocol.read_message_begin }.to raise_error(Thrift::ProtocolException)
275
+
276
+ response = buffer.read(buffer.available)
277
+ expect(response.bytesize).to be > 0
278
+ magic = response[4, 2].unpack('n').first
279
+ expect(magic).to eq(Thrift::HeaderTransport::HEADER_MAGIC)
280
+ end
281
+ end
282
+
283
+ describe "protocol auto-detection with legacy frames" do
284
+ it "should detect framed compact messages" do
285
+ write_buffer = Thrift::MemoryBufferTransport.new
286
+ write_protocol = Thrift::CompactProtocol.new(write_buffer)
287
+
288
+ write_protocol.write_message_begin("legacy_framed", Thrift::MessageTypes::CALL, 7)
289
+ write_protocol.write_struct_begin("Args")
290
+ write_protocol.write_field_stop
291
+ write_protocol.write_struct_end
292
+ write_protocol.write_message_end
293
+
294
+ payload = write_buffer.read(write_buffer.available)
295
+ framed = [payload.bytesize].pack('N') + payload
296
+
297
+ read_buffer = Thrift::MemoryBufferTransport.new(framed)
298
+ protocol = Thrift::HeaderProtocol.new(read_buffer)
299
+
300
+ name, type, seqid = protocol.read_message_begin
301
+ expect(name).to eq("legacy_framed")
302
+ expect(type).to eq(Thrift::MessageTypes::CALL)
303
+ expect(seqid).to eq(7)
304
+
305
+ protocol.read_struct_begin
306
+ _, field_type, _ = protocol.read_field_begin
307
+ expect(field_type).to eq(Thrift::Types::STOP)
308
+ protocol.read_struct_end
309
+ protocol.read_message_end
310
+ end
311
+
312
+ it "should detect unframed compact messages" do
313
+ write_buffer = Thrift::MemoryBufferTransport.new
314
+ write_protocol = Thrift::CompactProtocol.new(write_buffer)
315
+
316
+ write_protocol.write_message_begin("legacy_unframed", Thrift::MessageTypes::CALL, 9)
317
+ write_protocol.write_struct_begin("Args")
318
+ write_protocol.write_field_stop
319
+ write_protocol.write_struct_end
320
+ write_protocol.write_message_end
321
+
322
+ payload = write_buffer.read(write_buffer.available)
323
+
324
+ read_buffer = Thrift::MemoryBufferTransport.new(payload)
325
+ protocol = Thrift::HeaderProtocol.new(read_buffer)
326
+
327
+ name, type, seqid = protocol.read_message_begin
328
+ expect(name).to eq("legacy_unframed")
329
+ expect(type).to eq(Thrift::MessageTypes::CALL)
330
+ expect(seqid).to eq(9)
331
+
332
+ protocol.read_struct_begin
333
+ _, field_type, _ = protocol.read_field_begin
334
+ expect(field_type).to eq(Thrift::Types::STOP)
335
+ protocol.read_struct_end
336
+ protocol.read_message_end
337
+ end
338
+ end
339
+
340
+ describe "with compression" do
341
+ it "should work with ZLIB transform" do
342
+ @protocol.add_transform(Thrift::HeaderTransformID::ZLIB)
343
+
344
+ @protocol.write_message_begin("compressed_test", Thrift::MessageTypes::CALL, 42)
345
+ @protocol.write_struct_begin("Args")
346
+ @protocol.write_field_begin("data", Thrift::Types::STRING, 1)
347
+ @protocol.write_string("a" * 100) # Compressible data
348
+ @protocol.write_field_end
349
+ @protocol.write_field_stop
350
+ @protocol.write_struct_end
351
+ @protocol.write_message_end
352
+ @protocol.trans.flush
353
+
354
+ data = @buffer.read(@buffer.available)
355
+ read_buffer = Thrift::MemoryBufferTransport.new(data)
356
+ read_protocol = Thrift::HeaderProtocol.new(read_buffer)
357
+
358
+ name, type, seqid = read_protocol.read_message_begin
359
+ expect(name).to eq("compressed_test")
360
+ expect(seqid).to eq(42)
361
+
362
+ read_protocol.read_struct_begin
363
+ _, _, _ = read_protocol.read_field_begin
364
+ result = read_protocol.read_string
365
+ expect(result).to eq("a" * 100)
366
+ end
367
+ end
368
+
369
+ describe "containers" do
370
+ it "should write and read lists" do
371
+ @protocol.write_message_begin("test", Thrift::MessageTypes::CALL, 1)
372
+ @protocol.write_struct_begin("Test")
373
+ @protocol.write_field_begin("list", Thrift::Types::LIST, 1)
374
+ @protocol.write_list_begin(Thrift::Types::I32, 3)
375
+ @protocol.write_i32(1)
376
+ @protocol.write_i32(2)
377
+ @protocol.write_i32(3)
378
+ @protocol.write_list_end
379
+ @protocol.write_field_end
380
+ @protocol.write_field_stop
381
+ @protocol.write_struct_end
382
+ @protocol.write_message_end
383
+ @protocol.trans.flush
384
+
385
+ data = @buffer.read(@buffer.available)
386
+ read_buffer = Thrift::MemoryBufferTransport.new(data)
387
+ read_protocol = Thrift::HeaderProtocol.new(read_buffer)
388
+
389
+ read_protocol.read_message_begin
390
+ read_protocol.read_struct_begin
391
+ _, _, _ = read_protocol.read_field_begin
392
+ etype, size = read_protocol.read_list_begin
393
+ expect(etype).to eq(Thrift::Types::I32)
394
+ expect(size).to eq(3)
395
+ expect(read_protocol.read_i32).to eq(1)
396
+ expect(read_protocol.read_i32).to eq(2)
397
+ expect(read_protocol.read_i32).to eq(3)
398
+ end
399
+
400
+ it "should write and read maps" do
401
+ @protocol.write_message_begin("test", Thrift::MessageTypes::CALL, 1)
402
+ @protocol.write_struct_begin("Test")
403
+ @protocol.write_field_begin("map", Thrift::Types::MAP, 1)
404
+ @protocol.write_map_begin(Thrift::Types::STRING, Thrift::Types::I32, 2)
405
+ @protocol.write_string("a")
406
+ @protocol.write_i32(1)
407
+ @protocol.write_string("b")
408
+ @protocol.write_i32(2)
409
+ @protocol.write_map_end
410
+ @protocol.write_field_end
411
+ @protocol.write_field_stop
412
+ @protocol.write_struct_end
413
+ @protocol.write_message_end
414
+ @protocol.trans.flush
415
+
416
+ data = @buffer.read(@buffer.available)
417
+ read_buffer = Thrift::MemoryBufferTransport.new(data)
418
+ read_protocol = Thrift::HeaderProtocol.new(read_buffer)
419
+
420
+ read_protocol.read_message_begin
421
+ read_protocol.read_struct_begin
422
+ _, _, _ = read_protocol.read_field_begin
423
+ ktype, vtype, size = read_protocol.read_map_begin
424
+ expect(ktype).to eq(Thrift::Types::STRING)
425
+ expect(vtype).to eq(Thrift::Types::I32)
426
+ expect(size).to eq(2)
427
+ end
428
+
429
+ it "should write and read sets" do
430
+ @protocol.write_message_begin("test", Thrift::MessageTypes::CALL, 1)
431
+ @protocol.write_struct_begin("Test")
432
+ @protocol.write_field_begin("set", Thrift::Types::SET, 1)
433
+ @protocol.write_set_begin(Thrift::Types::STRING, 2)
434
+ @protocol.write_string("x")
435
+ @protocol.write_string("y")
436
+ @protocol.write_set_end
437
+ @protocol.write_field_end
438
+ @protocol.write_field_stop
439
+ @protocol.write_struct_end
440
+ @protocol.write_message_end
441
+ @protocol.trans.flush
442
+
443
+ data = @buffer.read(@buffer.available)
444
+ read_buffer = Thrift::MemoryBufferTransport.new(data)
445
+ read_protocol = Thrift::HeaderProtocol.new(read_buffer)
446
+
447
+ read_protocol.read_message_begin
448
+ read_protocol.read_struct_begin
449
+ _, _, _ = read_protocol.read_field_begin
450
+ etype, size = read_protocol.read_set_begin
451
+ expect(etype).to eq(Thrift::Types::STRING)
452
+ expect(size).to eq(2)
453
+ end
454
+ end
455
+ end
456
+
457
+ describe Thrift::HeaderProtocolFactory do
458
+ it "should create HeaderProtocol" do
459
+ factory = Thrift::HeaderProtocolFactory.new
460
+ buffer = Thrift::MemoryBufferTransport.new
461
+ protocol = factory.get_protocol(buffer)
462
+ expect(protocol).to be_a(Thrift::HeaderProtocol)
463
+ end
464
+
465
+ it "should provide a reasonable to_s" do
466
+ expect(Thrift::HeaderProtocolFactory.new.to_s).to eq("header")
467
+ end
468
+
469
+ it "should pass configuration to protocol" do
470
+ factory = Thrift::HeaderProtocolFactory.new(nil, Thrift::HeaderSubprotocolID::COMPACT)
471
+ buffer = Thrift::MemoryBufferTransport.new
472
+ protocol = factory.get_protocol(buffer)
473
+ expect(protocol.to_s).to match(/compact/)
474
+ end
475
+ end
476
+ end