thrift 0.22.0 → 0.23.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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +175 -17
  3. data/benchmark/benchmark.rb +22 -8
  4. data/benchmark/client.rb +49 -6
  5. data/benchmark/server.rb +45 -7
  6. data/benchmark/thin_server.rb +1 -0
  7. data/ext/binary_protocol_accelerated.c +76 -19
  8. data/ext/compact_protocol.c +80 -15
  9. data/ext/constants.h +12 -0
  10. data/ext/extconf.rb +10 -9
  11. data/ext/memory_buffer.c +7 -7
  12. data/ext/protocol.c +29 -0
  13. data/ext/protocol.h +35 -0
  14. data/ext/struct.c +36 -5
  15. data/ext/thrift_native.c +27 -3
  16. data/lib/thrift/bytes.rb +68 -101
  17. data/lib/thrift/client.rb +61 -9
  18. data/lib/thrift/exceptions.rb +5 -5
  19. data/lib/thrift/multiplexed_processor.rb +6 -6
  20. data/lib/thrift/processor.rb +6 -6
  21. data/lib/thrift/protocol/base_protocol.rb +37 -15
  22. data/lib/thrift/protocol/binary_protocol.rb +25 -9
  23. data/lib/thrift/protocol/binary_protocol_accelerated.rb +5 -5
  24. data/lib/thrift/protocol/compact_protocol.rb +61 -37
  25. data/lib/thrift/protocol/header_protocol.rb +320 -0
  26. data/lib/thrift/protocol/json_protocol.rb +26 -16
  27. data/lib/thrift/protocol/multiplexed_protocol.rb +5 -5
  28. data/lib/thrift/protocol/protocol_decorator.rb +12 -4
  29. data/lib/thrift/serializer/deserializer.rb +5 -5
  30. data/lib/thrift/serializer/serializer.rb +4 -5
  31. data/lib/thrift/server/base_server.rb +4 -4
  32. data/lib/thrift/server/mongrel_http_server.rb +6 -6
  33. data/lib/thrift/server/nonblocking_server.rb +8 -8
  34. data/lib/thrift/server/simple_server.rb +4 -4
  35. data/lib/thrift/server/thin_http_server.rb +3 -3
  36. data/lib/thrift/server/thread_pool_server.rb +6 -6
  37. data/lib/thrift/server/threaded_server.rb +4 -4
  38. data/lib/thrift/struct.rb +11 -11
  39. data/lib/thrift/struct_union.rb +19 -9
  40. data/lib/thrift/thrift_native.rb +1 -1
  41. data/lib/thrift/transport/base_server_transport.rb +5 -5
  42. data/lib/thrift/transport/base_transport.rb +12 -12
  43. data/lib/thrift/transport/buffered_transport.rb +6 -6
  44. data/lib/thrift/transport/framed_transport.rb +7 -7
  45. data/lib/thrift/transport/header_transport.rb +516 -0
  46. data/lib/thrift/transport/http_client_transport.rb +1 -1
  47. data/lib/thrift/transport/io_stream_transport.rb +3 -3
  48. data/lib/thrift/transport/memory_buffer_transport.rb +6 -6
  49. data/lib/thrift/transport/server_socket.rb +8 -5
  50. data/lib/thrift/transport/socket.rb +58 -31
  51. data/lib/thrift/transport/ssl_server_socket.rb +1 -1
  52. data/lib/thrift/transport/ssl_socket.rb +2 -2
  53. data/lib/thrift/transport/unix_server_socket.rb +4 -4
  54. data/lib/thrift/transport/unix_socket.rb +6 -6
  55. data/lib/thrift/types.rb +9 -6
  56. data/lib/thrift/union.rb +14 -8
  57. data/lib/thrift/uuid.rb +49 -0
  58. data/lib/thrift.rb +3 -1
  59. data/spec/ThriftSpec.thrift +5 -1
  60. data/spec/base_protocol_spec.rb +1 -2
  61. data/spec/base_transport_spec.rb +6 -7
  62. data/spec/binary_protocol_spec.rb +0 -2
  63. data/spec/binary_protocol_spec_shared.rb +129 -142
  64. data/spec/bytes_spec.rb +57 -118
  65. data/spec/client_spec.rb +85 -19
  66. data/spec/compact_protocol_spec.rb +54 -16
  67. data/spec/constants_demo_spec.rb +101 -0
  68. data/spec/exception_spec.rb +0 -1
  69. data/spec/header_protocol_spec.rb +475 -0
  70. data/spec/header_transport_spec.rb +386 -0
  71. data/spec/http_client_spec.rb +4 -6
  72. data/spec/json_protocol_spec.rb +47 -47
  73. data/spec/namespaced_spec.rb +0 -1
  74. data/spec/nonblocking_server_spec.rb +102 -4
  75. data/spec/processor_spec.rb +0 -1
  76. data/spec/serializer_spec.rb +0 -1
  77. data/spec/server_socket_spec.rb +1 -1
  78. data/spec/server_spec.rb +8 -9
  79. data/spec/socket_spec.rb +0 -1
  80. data/spec/socket_spec_shared.rb +72 -9
  81. data/spec/spec_helper.rb +1 -1
  82. data/spec/ssl_server_socket_spec.rb +12 -1
  83. data/spec/ssl_socket_spec.rb +10 -1
  84. data/spec/struct_nested_containers_spec.rb +1 -2
  85. data/spec/struct_spec.rb +113 -9
  86. data/spec/support/header_protocol_helper.rb +54 -0
  87. data/spec/thin_http_server_spec.rb +3 -18
  88. data/spec/types_spec.rb +25 -26
  89. data/spec/union_spec.rb +69 -11
  90. data/spec/unix_socket_spec.rb +1 -2
  91. data/spec/uuid_validation_spec.rb +238 -0
  92. data/test/fuzz/Makefile.am +173 -0
  93. data/test/fuzz/README.md +149 -0
  94. data/test/fuzz/fuzz_common.rb +95 -0
  95. data/{lib/thrift/core_ext.rb → test/fuzz/fuzz_parse_binary_protocol.rb} +3 -4
  96. data/{lib/thrift/core_ext/fixnum.rb → test/fuzz/fuzz_parse_binary_protocol_accelerated.rb} +6 -13
  97. data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +22 -0
  98. data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +22 -0
  99. data/test/fuzz/fuzz_parse_compact_protocol.rb +22 -0
  100. data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +22 -0
  101. data/test/fuzz/fuzz_parse_json_protocol.rb +22 -0
  102. data/test/fuzz/fuzz_parse_json_protocol_harness.rb +22 -0
  103. data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +22 -0
  104. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +22 -0
  105. data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +22 -0
  106. data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +22 -0
  107. data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +22 -0
  108. data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +22 -0
  109. data/test/fuzz/fuzz_roundtrip_json_protocol.rb +22 -0
  110. data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +22 -0
  111. data/test/fuzz/fuzz_tracer.rb +28 -0
  112. metadata +106 -37
@@ -22,13 +22,10 @@ require 'rack/test'
22
22
  require 'thrift/server/thin_http_server'
23
23
 
24
24
  describe Thrift::ThinHTTPServer do
25
-
26
25
  let(:processor) { double('processor') }
27
26
 
28
27
  describe "#initialize" do
29
-
30
28
  context "when using the defaults" do
31
-
32
29
  it "binds to port 80, with host 0.0.0.0, a path of '/'" do
33
30
  expect(Thin::Server).to receive(:new).with('0.0.0.0', 80, an_instance_of(Rack::Builder))
34
31
  Thrift::ThinHTTPServer.new(processor)
@@ -43,11 +40,9 @@ describe Thrift::ThinHTTPServer do
43
40
  expect(Thrift::BinaryProtocolFactory).to receive(:new)
44
41
  Thrift::ThinHTTPServer.new(processor)
45
42
  end
46
-
47
43
  end
48
44
 
49
45
  context "when using the options" do
50
-
51
46
  it 'accepts :ip, :port, :path' do
52
47
  ip = "192.168.0.1"
53
48
  port = 3000
@@ -64,13 +59,10 @@ describe Thrift::ThinHTTPServer do
64
59
  Thrift::ThinHTTPServer.new(processor,
65
60
  :protocol_factory => Thrift::JsonProtocolFactory.new)
66
61
  end
67
-
68
62
  end
69
-
70
63
  end
71
64
 
72
65
  describe "#serve" do
73
-
74
66
  it 'starts the Thin server' do
75
67
  underlying_thin_server = double('thin server', :start => true)
76
68
  allow(Thin::Server).to receive(:new).and_return(underlying_thin_server)
@@ -81,7 +73,6 @@ describe Thrift::ThinHTTPServer do
81
73
  thin_thrift_server.serve
82
74
  end
83
75
  end
84
-
85
76
  end
86
77
 
87
78
  describe Thrift::ThinHTTPServer::RackApplication do
@@ -95,23 +86,20 @@ describe Thrift::ThinHTTPServer::RackApplication do
95
86
  end
96
87
 
97
88
  context "404 response" do
98
-
99
89
  it 'receives a non-POST' do
100
90
  header('Content-Type', "application/x-thrift")
101
91
  get "/"
102
- expect(last_response.status).to be 404
92
+ expect(last_response.status).to eq 404
103
93
  end
104
94
 
105
95
  it 'receives a header other than application/x-thrift' do
106
96
  header('Content-Type', "application/json")
107
97
  post "/"
108
- expect(last_response.status).to be 404
98
+ expect(last_response.status).to eq 404
109
99
  end
110
-
111
100
  end
112
101
 
113
102
  context "200 response" do
114
-
115
103
  before do
116
104
  allow(protocol_factory).to receive(:get_protocol)
117
105
  allow(processor).to receive(:process)
@@ -132,10 +120,7 @@ describe Thrift::ThinHTTPServer::RackApplication do
132
120
  it 'status code 200' do
133
121
  header('Content-Type', "application/x-thrift")
134
122
  post "/"
135
- expect(last_response.ok?).to be_truthy
123
+ expect(last_response.ok?).to be true
136
124
  end
137
-
138
125
  end
139
-
140
126
  end
141
-
data/spec/types_spec.rb CHANGED
@@ -20,7 +20,6 @@
20
20
  require 'spec_helper'
21
21
 
22
22
  describe Thrift::Types do
23
-
24
23
  before(:each) do
25
24
  Thrift.type_checking = true
26
25
  end
@@ -39,33 +38,33 @@ describe Thrift::Types do
39
38
 
40
39
  it "should check types properly" do
41
40
  # lambda { Thrift.check_type(nil, Thrift::Types::STOP) }.should raise_error(Thrift::TypeError)
42
- expect { Thrift.check_type(3, {:type => Thrift::Types::STOP}, :foo) }.to raise_error(Thrift::TypeError)
43
- expect { Thrift.check_type(nil, {:type => Thrift::Types::VOID}, :foo) }.not_to raise_error
44
- expect { Thrift.check_type(3, {:type => Thrift::Types::VOID}, :foo) }.to raise_error(Thrift::TypeError)
45
- expect { Thrift.check_type(true, {:type => Thrift::Types::BOOL}, :foo) }.not_to raise_error
46
- expect { Thrift.check_type(3, {:type => Thrift::Types::BOOL}, :foo) }.to raise_error(Thrift::TypeError)
47
- expect { Thrift.check_type(42, {:type => Thrift::Types::BYTE}, :foo) }.not_to raise_error
48
- expect { Thrift.check_type(42, {:type => Thrift::Types::I16}, :foo) }.not_to raise_error
49
- expect { Thrift.check_type(42, {:type => Thrift::Types::I32}, :foo) }.not_to raise_error
50
- expect { Thrift.check_type(42, {:type => Thrift::Types::I64}, :foo) }.not_to raise_error
51
- expect { Thrift.check_type(3.14, {:type => Thrift::Types::I32}, :foo) }.to raise_error(Thrift::TypeError)
52
- expect { Thrift.check_type(3.14, {:type => Thrift::Types::DOUBLE}, :foo) }.not_to raise_error
53
- expect { Thrift.check_type(3, {:type => Thrift::Types::DOUBLE}, :foo) }.to raise_error(Thrift::TypeError)
54
- expect { Thrift.check_type("3", {:type => Thrift::Types::STRING}, :foo) }.not_to raise_error
55
- expect { Thrift.check_type(3, {:type => Thrift::Types::STRING}, :foo) }.to raise_error(Thrift::TypeError)
41
+ expect { Thrift.check_type(3, {:type => Thrift::Types::STOP}, :foo) }.to raise_error(Thrift::TypeError)
42
+ expect { Thrift.check_type(nil, {:type => Thrift::Types::VOID}, :foo) }.not_to raise_error
43
+ expect { Thrift.check_type(3, {:type => Thrift::Types::VOID}, :foo) }.to raise_error(Thrift::TypeError)
44
+ expect { Thrift.check_type(true, {:type => Thrift::Types::BOOL}, :foo) }.not_to raise_error
45
+ expect { Thrift.check_type(3, {:type => Thrift::Types::BOOL}, :foo) }.to raise_error(Thrift::TypeError)
46
+ expect { Thrift.check_type(42, {:type => Thrift::Types::BYTE}, :foo) }.not_to raise_error
47
+ expect { Thrift.check_type(42, {:type => Thrift::Types::I16}, :foo) }.not_to raise_error
48
+ expect { Thrift.check_type(42, {:type => Thrift::Types::I32}, :foo) }.not_to raise_error
49
+ expect { Thrift.check_type(42, {:type => Thrift::Types::I64}, :foo) }.not_to raise_error
50
+ expect { Thrift.check_type(3.14, {:type => Thrift::Types::I32}, :foo) }.to raise_error(Thrift::TypeError)
51
+ expect { Thrift.check_type(3.14, {:type => Thrift::Types::DOUBLE}, :foo) }.not_to raise_error
52
+ expect { Thrift.check_type(3, {:type => Thrift::Types::DOUBLE}, :foo) }.to raise_error(Thrift::TypeError)
53
+ expect { Thrift.check_type("3", {:type => Thrift::Types::STRING}, :foo) }.not_to raise_error
54
+ expect { Thrift.check_type(3, {:type => Thrift::Types::STRING}, :foo) }.to raise_error(Thrift::TypeError)
56
55
  hello = SpecNamespace::Hello.new
57
- expect { Thrift.check_type(hello, {:type => Thrift::Types::STRUCT, :class => SpecNamespace::Hello}, :foo) }.not_to raise_error
58
- expect { Thrift.check_type("foo", {:type => Thrift::Types::STRUCT}, :foo) }.to raise_error(Thrift::TypeError)
56
+ expect { Thrift.check_type(hello, {:type => Thrift::Types::STRUCT, :class => SpecNamespace::Hello}, :foo) }.not_to raise_error
57
+ expect { Thrift.check_type("foo", {:type => Thrift::Types::STRUCT}, :foo) }.to raise_error(Thrift::TypeError)
59
58
  field = {:type => Thrift::Types::MAP, :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRING}}
60
- expect { Thrift.check_type({1 => "one"}, field, :foo) }.not_to raise_error
61
- expect { Thrift.check_type([1], field, :foo) }.to raise_error(Thrift::TypeError)
59
+ expect { Thrift.check_type({1 => "one"}, field, :foo) }.not_to raise_error
60
+ expect { Thrift.check_type([1], field, :foo) }.to raise_error(Thrift::TypeError)
62
61
  field = {:type => Thrift::Types::LIST, :element => {:type => Thrift::Types::I32}}
63
- expect { Thrift.check_type([1], field, :foo) }.not_to raise_error
64
- expect { Thrift.check_type({:foo => 1}, field, :foo) }.to raise_error(Thrift::TypeError)
62
+ expect { Thrift.check_type([1], field, :foo) }.not_to raise_error
63
+ expect { Thrift.check_type({:foo => 1}, field, :foo) }.to raise_error(Thrift::TypeError)
65
64
  field = {:type => Thrift::Types::SET, :element => {:type => Thrift::Types::I32}}
66
- expect { Thrift.check_type(Set.new([1,2]), field, :foo) }.not_to raise_error
67
- expect { Thrift.check_type([1,2], field, :foo) }.to raise_error(Thrift::TypeError)
68
- expect { Thrift.check_type({:foo => true}, field, :foo) }.to raise_error(Thrift::TypeError)
65
+ expect { Thrift.check_type(Set.new([1, 2]), field, :foo) }.not_to raise_error
66
+ expect { Thrift.check_type([1, 2], field, :foo) }.to raise_error(Thrift::TypeError)
67
+ expect { Thrift.check_type({:foo => true}, field, :foo) }.to raise_error(Thrift::TypeError)
69
68
  end
70
69
 
71
70
  it "should error out if nil is passed and skip_types is false" do
@@ -100,9 +99,9 @@ describe Thrift::Types do
100
99
  end
101
100
 
102
101
  it "should give the Thrift::TypeError a readable message" do
103
- msg = /Expected Types::STRING, received (Integer|Fixnum) for field foo/
102
+ msg = "Expected Types::STRING, received Integer for field foo"
104
103
  expect { Thrift.check_type(3, {:type => Thrift::Types::STRING}, :foo) }.to raise_error(Thrift::TypeError, msg)
105
- msg = /Expected Types::STRING, received (Integer|Fixnum) for field foo.element/
104
+ msg = "Expected Types::STRING, received Integer for field foo.element"
106
105
  field = {:type => Thrift::Types::LIST, :element => {:type => Thrift::Types::STRING}}
107
106
  expect { Thrift.check_type([3], field, :foo) }.to raise_error(Thrift::TypeError, msg)
108
107
  msg = "Expected Types::I32, received NilClass for field foo.element.key"
data/spec/union_spec.rb CHANGED
@@ -20,7 +20,6 @@
20
20
  require 'spec_helper'
21
21
 
22
22
  describe 'Union' do
23
-
24
23
  describe Thrift::Union do
25
24
  it "should return nil value in unset union" do
26
25
  union = SpecNamespace::My_union.new
@@ -51,7 +50,9 @@ describe 'Union' do
51
50
  it "should raise for wrong set field when hash initialized and type checking is off" do
52
51
  Thrift.type_checking = false
53
52
  union = SpecNamespace::My_union.new({incorrect_field: :incorrect})
54
- expect { Thrift::Serializer.new.serialize(union) }.to raise_error(RuntimeError, "set_field is not valid for this union!")
53
+ expect { Thrift::Serializer.new.serialize(union) }.to raise_error(Thrift::ProtocolException, "set_field is not valid for this union!") { |error|
54
+ expect(error.type).to eq(Thrift::ProtocolException::INVALID_DATA)
55
+ }
55
56
  end
56
57
 
57
58
  it "should not be equal to nil" do
@@ -91,6 +92,24 @@ describe 'Union' do
91
92
  expect(union).not_to eq(other_union)
92
93
  end
93
94
 
95
+ it "should equate two unions with the same UUID value" do
96
+ union = SpecNamespace::My_union.new(:unique_id, '550e8400-e29b-41d4-a716-446655440000')
97
+ other_union = SpecNamespace::My_union.new(:unique_id, '550e8400-e29b-41d4-a716-446655440000')
98
+ expect(union).to eq(other_union)
99
+ end
100
+
101
+ it "should not equate two unions with different UUID values" do
102
+ union = SpecNamespace::My_union.new(:unique_id, '550e8400-e29b-41d4-a716-446655440000')
103
+ other_union = SpecNamespace::My_union.new(:unique_id, '6ba7b810-9dad-11d1-80b4-00c04fd430c8')
104
+ expect(union).not_to eq(other_union)
105
+ end
106
+
107
+ it "should not equate UUID union with different field type" do
108
+ union = SpecNamespace::My_union.new(:unique_id, '550e8400-e29b-41d4-a716-446655440000')
109
+ other_union = SpecNamespace::My_union.new(:some_characters, '550e8400-e29b-41d4-a716-446655440000')
110
+ expect(union).not_to eq(other_union)
111
+ end
112
+
94
113
  it "should inspect properly" do
95
114
  union = SpecNamespace::My_union.new(:integer32, 25)
96
115
  expect(union.inspect).to eq("<SpecNamespace::My_union integer32: 25>")
@@ -130,7 +149,9 @@ describe 'Union' do
130
149
 
131
150
  it "should raise when validating unset union" do
132
151
  union = SpecNamespace::My_union.new
133
- expect { union.validate }.to raise_error(StandardError, "Union fields are not set.")
152
+ expect { union.validate }.to raise_error(Thrift::ProtocolException, "Union fields are not set.") { |error|
153
+ expect(error.type).to eq(Thrift::ProtocolException::INVALID_DATA)
154
+ }
134
155
 
135
156
  other_union = SpecNamespace::My_union.new(:integer32, 1)
136
157
  expect { other_union.validate }.not_to raise_error
@@ -139,7 +160,9 @@ describe 'Union' do
139
160
  it "should validate an enum field properly" do
140
161
  union = SpecNamespace::TestUnion.new(:enum_field, 3)
141
162
  expect(union.get_set_field).to eq(:enum_field)
142
- expect { union.validate }.to raise_error(Thrift::ProtocolException, "Invalid value of field enum_field!")
163
+ expect { union.validate }.to raise_error(Thrift::ProtocolException, "Invalid value of field enum_field!") { |error|
164
+ expect(error.type).to eq(Thrift::ProtocolException::INVALID_DATA)
165
+ }
143
166
 
144
167
  other_union = SpecNamespace::TestUnion.new(:enum_field, 1)
145
168
  expect { other_union.validate }.not_to raise_error
@@ -170,7 +193,7 @@ describe 'Union' do
170
193
  end
171
194
 
172
195
  it "should not throw an error when inspected and unset" do
173
- expect{SpecNamespace::TestUnion.new().inspect}.not_to raise_error
196
+ expect{ SpecNamespace::TestUnion.new().inspect }.not_to raise_error
174
197
  end
175
198
 
176
199
  it "should print enum value name when inspected" do
@@ -192,23 +215,58 @@ describe 'Union' do
192
215
 
193
216
  it "should be comparable" do
194
217
  relationships = [
195
- [0, -1, -1, -1],
196
- [1, 0, -1, -1],
197
- [1, 1, 0, -1],
198
- [1, 1, 1, 0]]
218
+ [0, -1, -1, -1, -1, -1],
219
+ [1, 0, -1, -1, -1, -1],
220
+ [1, 1, 0, -1, -1, -1],
221
+ [1, 1, 1, 0, -1, -1],
222
+ [1, 1, 1, 1, 0, -1],
223
+ [1, 1, 1, 1, 1, 0]]
199
224
 
200
225
  objs = [
201
226
  SpecNamespace::TestUnion.new(:string_field, "blah"),
202
227
  SpecNamespace::TestUnion.new(:string_field, "blahblah"),
203
228
  SpecNamespace::TestUnion.new(:i32_field, 1),
229
+ SpecNamespace::TestUnion.new(:uuid_field, '550e8400-e29b-41d4-a716-446655440000'),
230
+ SpecNamespace::TestUnion.new(:uuid_field, '6ba7b810-9dad-11d1-80b4-00c04fd430c8'),
204
231
  SpecNamespace::TestUnion.new()]
205
232
 
206
- for y in 0..3
207
- for x in 0..3
233
+ objs.size.times do |y|
234
+ objs.size.times do |x|
208
235
  # puts "#{objs[y].inspect} <=> #{objs[x].inspect} should == #{relationships[y][x]}"
209
236
  expect(objs[y] <=> objs[x]).to eq(relationships[y][x])
210
237
  end
211
238
  end
212
239
  end
240
+
241
+ it "should handle UUID as union value" do
242
+ union = SpecNamespace::My_union.new
243
+ union.unique_id = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
244
+
245
+ trans = Thrift::MemoryBufferTransport.new
246
+ prot = Thrift::CompactProtocol.new(trans)
247
+
248
+ union.write(prot)
249
+
250
+ result = SpecNamespace::My_union.new
251
+ result.read(prot)
252
+
253
+ expect(result.unique_id).to eq('ffffffff-ffff-ffff-ffff-ffffffffffff')
254
+ expect(result.get_set_field).to eq(:unique_id)
255
+ end
256
+
257
+ it "should normalize UUID case in union" do
258
+ union = SpecNamespace::My_union.new
259
+ union.unique_id = '550E8400-E29B-41D4-A716-446655440000'
260
+
261
+ trans = Thrift::MemoryBufferTransport.new
262
+ prot = Thrift::BinaryProtocol.new(trans)
263
+
264
+ union.write(prot)
265
+
266
+ result = SpecNamespace::My_union.new
267
+ result.read(prot)
268
+
269
+ expect(result.unique_id).to eq('550e8400-e29b-41d4-a716-446655440000')
270
+ end
213
271
  end
214
272
  end
@@ -21,7 +21,6 @@ require 'spec_helper'
21
21
  require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared")
22
22
 
23
23
  describe 'UNIXSocket' do
24
-
25
24
  describe Thrift::UNIXSocket do
26
25
  before(:each) do
27
26
  @path = '/tmp/thrift_spec_socket'
@@ -42,7 +41,7 @@ describe 'UNIXSocket' do
42
41
  allow(::UNIXSocket).to receive(:new)
43
42
  expect(Thrift::UNIXSocket.new(@path, 5).timeout).to eq(5)
44
43
  end
45
-
44
+
46
45
  it "should provide a reasonable to_s" do
47
46
  allow(::UNIXSocket).to receive(:new)
48
47
  expect(Thrift::UNIXSocket.new(@path).to_s).to eq("domain(#{@path})")
@@ -0,0 +1,238 @@
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 'UUID Validation' do
23
+ protocols = [
24
+ ['BinaryProtocol', Thrift::BinaryProtocol],
25
+ ]
26
+
27
+ if defined?(Thrift::BinaryProtocolAccelerated)
28
+ protocols << ['BinaryProtocolAccelerated', Thrift::BinaryProtocolAccelerated]
29
+ end
30
+
31
+ protocols << ['CompactProtocol', Thrift::CompactProtocol]
32
+ protocols << ['JsonProtocol', Thrift::JsonProtocol]
33
+
34
+ protocols.each do |protocol_name, protocol_class|
35
+ describe protocol_name do
36
+ before(:each) do
37
+ @trans = Thrift::MemoryBufferTransport.new
38
+ @prot = protocol_class.new(@trans)
39
+ end
40
+
41
+ context 'valid UUIDs' do
42
+ it 'should accept lowercase UUIDs' do
43
+ uuid = '550e8400-e29b-41d4-a716-446655440000'
44
+ expect { @prot.write_uuid(uuid) }.not_to raise_error
45
+ result = @prot.read_uuid
46
+ expect(result).to eq(uuid)
47
+ end
48
+
49
+ it 'should accept uppercase UUIDs' do
50
+ uuid = '550E8400-E29B-41D4-A716-446655440000'
51
+ expect { @prot.write_uuid(uuid) }.not_to raise_error
52
+ result = @prot.read_uuid
53
+ # Result should be lowercase
54
+ expect(result).to eq('550e8400-e29b-41d4-a716-446655440000')
55
+ end
56
+
57
+ it 'should accept mixed case UUIDs' do
58
+ uuid = '550e8400-E29B-41d4-A716-446655440000'
59
+ expect { @prot.write_uuid(uuid) }.not_to raise_error
60
+ result = @prot.read_uuid
61
+ expect(result).to eq('550e8400-e29b-41d4-a716-446655440000')
62
+ end
63
+
64
+ it 'should accept all zeros' do
65
+ uuid = '00000000-0000-0000-0000-000000000000'
66
+ expect { @prot.write_uuid(uuid) }.not_to raise_error
67
+ result = @prot.read_uuid
68
+ expect(result).to eq(uuid)
69
+ end
70
+
71
+ it 'should accept all fs' do
72
+ uuid = 'ffffffff-ffff-ffff-ffff-ffffffffffff'
73
+ expect { @prot.write_uuid(uuid) }.not_to raise_error
74
+ result = @prot.read_uuid
75
+ expect(result).to eq(uuid)
76
+ end
77
+ end
78
+
79
+ context 'invalid UUIDs' do
80
+ def expect_invalid_uuid(value, message)
81
+ expect { @prot.write_uuid(value) }.to raise_error(Thrift::ProtocolException) do |error|
82
+ expect(error.type).to eq(Thrift::ProtocolException::INVALID_DATA)
83
+ expect(error.message).to eq(message)
84
+ end
85
+ end
86
+
87
+ it 'should reject nil' do
88
+ expect_invalid_uuid(nil, 'UUID must be a string')
89
+ end
90
+
91
+ it 'should reject non-string' do
92
+ expect_invalid_uuid(12345, 'UUID must be a string')
93
+ end
94
+
95
+ it 'should reject wrong length' do
96
+ expect_invalid_uuid('550e8400-e29b-41d4-a716', 'Invalid UUID format')
97
+ end
98
+
99
+ it 'should reject missing hyphens' do
100
+ expect_invalid_uuid('550e8400e29b41d4a716446655440000', 'Invalid UUID format')
101
+ end
102
+
103
+ it 'should reject hyphens in wrong positions' do
104
+ expect_invalid_uuid('550e840-0e29b-41d4-a716-446655440000', 'Invalid UUID format')
105
+ end
106
+
107
+ it 'should reject invalid hex characters (g)' do
108
+ expect_invalid_uuid('550e8400-e29b-41d4-a716-44665544000g', 'Invalid UUID format')
109
+ end
110
+
111
+ it 'should reject invalid hex characters (z)' do
112
+ expect_invalid_uuid('z50e8400-e29b-41d4-a716-446655440000', 'Invalid UUID format')
113
+ end
114
+
115
+ it 'should reject invalid hex characters (space)' do
116
+ expect_invalid_uuid('550e8400-e29b-41d4-a716-44665544000 ', 'Invalid UUID format')
117
+ end
118
+
119
+ it 'should reject empty string' do
120
+ expect_invalid_uuid('', 'Invalid UUID format')
121
+ end
122
+
123
+ it 'should reject UUID with extra characters' do
124
+ expect_invalid_uuid('550e8400-e29b-41d4-a716-446655440000x', 'Invalid UUID format')
125
+ end
126
+
127
+ it 'should reject trailing hyphen' do
128
+ expect_invalid_uuid('550e8400-e29b-41d4-a716-44665544000-', 'Invalid UUID format')
129
+ end
130
+
131
+ it 'should reject hyphen inside hex pair' do
132
+ expect_invalid_uuid('550e8400-e29b-41d4-a716-4466-5544000', 'Invalid UUID format')
133
+ end
134
+ end
135
+
136
+ context 'malformed binary data on read' do
137
+ it 'should raise error on truncated data' do
138
+ @trans = Thrift::MemoryBufferTransport.new
139
+ @prot = protocol_class.new(@trans)
140
+
141
+ # Write only 10 bytes instead of 16
142
+ if protocol_class == Thrift::JsonProtocol
143
+ @trans.write('"00000000-0000-0000-0000"')
144
+ else
145
+ @trans.write("\x00" * 10)
146
+ end
147
+
148
+ expect { @prot.read_uuid }.to raise_error(EOFError)
149
+ end
150
+
151
+ it 'should raise error on 15 bytes (one byte short)' do
152
+ @trans = Thrift::MemoryBufferTransport.new
153
+ @prot = protocol_class.new(@trans)
154
+
155
+ if protocol_class == Thrift::JsonProtocol
156
+ @trans.write('"00000000-0000-0000-0000-000000000"')
157
+ else
158
+ @trans.write("\x00" * 15)
159
+ end
160
+
161
+ expect { @prot.read_uuid }.to raise_error(EOFError)
162
+ end
163
+
164
+ it 'should raise error on empty buffer' do
165
+ @trans = Thrift::MemoryBufferTransport.new
166
+ @prot = protocol_class.new(@trans)
167
+
168
+ expect { @prot.read_uuid }.to raise_error(EOFError)
169
+ end
170
+ end
171
+
172
+ context 'multiple UUIDs in sequence' do
173
+ it 'should handle 10 UUIDs in sequence' do
174
+ uuids = 10.times.map { |i| sprintf('%08x-0000-0000-0000-000000000000', i) }
175
+
176
+ @trans = Thrift::MemoryBufferTransport.new
177
+ @prot = protocol_class.new(@trans)
178
+
179
+ uuids.each { |uuid| @prot.write_uuid(uuid) }
180
+
181
+ results = 10.times.map { @prot.read_uuid }
182
+ expect(results).to eq(uuids)
183
+ end
184
+
185
+ it 'should handle UUIDs interleaved with other types' do
186
+ @trans = Thrift::MemoryBufferTransport.new
187
+ @prot = protocol_class.new(@trans)
188
+
189
+ @prot.write_message_begin('testMessage', Thrift::MessageTypes::CALL, 0)
190
+ @prot.write_i32(42)
191
+ @prot.write_uuid('550e8400-e29b-41d4-a716-446655440000')
192
+ @prot.write_string('test')
193
+ @prot.write_uuid('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
194
+ @prot.write_i64(123456789)
195
+ @prot.write_message_end
196
+
197
+ @prot.read_message_begin
198
+ expect(@prot.read_i32).to eq(42)
199
+ expect(@prot.read_uuid).to eq('550e8400-e29b-41d4-a716-446655440000')
200
+ expect(@prot.read_string).to eq('test')
201
+ expect(@prot.read_uuid).to eq('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
202
+ expect(@prot.read_i64).to eq(123456789)
203
+ @prot.read_message_end
204
+ end
205
+
206
+ it 'should handle UUIDs in struct fields context' do
207
+ @trans = Thrift::MemoryBufferTransport.new
208
+ @prot = protocol_class.new(@trans)
209
+
210
+ # Simulate struct field headers
211
+ @prot.write_struct_begin('test')
212
+ @prot.write_field_begin('uuid1', Thrift::Types::UUID, 1)
213
+ @prot.write_uuid('550e8400-e29b-41d4-a716-446655440000')
214
+ @prot.write_field_end
215
+ @prot.write_field_begin('uuid2', Thrift::Types::UUID, 2)
216
+ @prot.write_uuid('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
217
+ @prot.write_field_end
218
+ @prot.write_field_stop
219
+ @prot.write_struct_end
220
+
221
+ @prot.read_struct_begin
222
+ name, type, id = @prot.read_field_begin
223
+ expect(type).to eq(Thrift::Types::UUID)
224
+ expect(@prot.read_uuid).to eq('550e8400-e29b-41d4-a716-446655440000')
225
+ @prot.read_field_end
226
+
227
+ name, type, id = @prot.read_field_begin
228
+ expect(type).to eq(Thrift::Types::UUID)
229
+ expect(@prot.read_uuid).to eq('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
230
+ @prot.read_field_end
231
+
232
+ name, type, id = @prot.read_field_begin
233
+ expect(type).to eq(Thrift::Types::STOP)
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end