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.
- checksums.yaml +4 -4
- data/README.md +235 -17
- data/benchmark/benchmark.rb +23 -8
- data/benchmark/client.rb +50 -6
- data/benchmark/server.rb +46 -7
- data/benchmark/thin_server.rb +2 -0
- data/ext/binary_protocol_accelerated.c +154 -42
- data/ext/bytes.c +14 -0
- data/ext/compact_protocol.c +138 -45
- data/ext/constants.h +12 -0
- data/ext/extconf.rb +17 -8
- data/ext/memory_buffer.c +44 -7
- data/ext/protocol.c +29 -0
- data/ext/protocol.h +35 -0
- data/ext/struct.c +48 -17
- data/ext/thrift_native.c +28 -3
- data/lib/thrift/bytes.rb +70 -100
- data/lib/thrift/client.rb +54 -13
- data/lib/thrift/exceptions.rb +6 -5
- data/lib/thrift/multiplexed_processor.rb +20 -10
- data/lib/thrift/processor.rb +7 -6
- data/lib/thrift/protocol/base_protocol.rb +52 -21
- data/lib/thrift/protocol/binary_protocol.rb +65 -20
- data/lib/thrift/protocol/binary_protocol_accelerated.rb +6 -5
- data/lib/thrift/protocol/compact_protocol.rb +76 -41
- data/lib/thrift/protocol/header_protocol.rb +321 -0
- data/lib/thrift/protocol/json_protocol.rb +44 -27
- data/lib/thrift/protocol/multiplexed_protocol.rb +6 -5
- data/lib/thrift/protocol/protocol_decorator.rb +13 -4
- data/lib/thrift/serializer/deserializer.rb +6 -5
- data/lib/thrift/serializer/serializer.rb +5 -5
- data/lib/thrift/server/base_server.rb +5 -4
- data/lib/thrift/server/mongrel_http_server.rb +7 -6
- data/lib/thrift/server/nonblocking_server.rb +35 -9
- data/lib/thrift/server/simple_server.rb +13 -5
- data/lib/thrift/server/thin_http_server.rb +4 -3
- data/lib/thrift/server/thread_pool_server.rb +7 -6
- data/lib/thrift/server/threaded_server.rb +13 -5
- data/lib/thrift/struct.rb +12 -11
- data/lib/thrift/struct_union.rb +14 -9
- data/lib/thrift/thrift_native.rb +3 -2
- data/lib/thrift/transport/base_server_transport.rb +8 -5
- data/lib/thrift/transport/base_transport.rb +18 -14
- data/lib/thrift/transport/buffered_transport.rb +7 -6
- data/lib/thrift/transport/framed_transport.rb +8 -7
- data/lib/thrift/transport/header_transport.rb +562 -0
- data/lib/thrift/transport/http_client_transport.rb +2 -1
- data/lib/thrift/transport/io_stream_transport.rb +4 -3
- data/lib/thrift/transport/memory_buffer_transport.rb +13 -6
- data/lib/thrift/transport/server_socket.rb +14 -8
- data/lib/thrift/transport/socket.rb +126 -60
- data/lib/thrift/transport/ssl_server_socket.rb +4 -3
- data/lib/thrift/transport/ssl_socket.rb +45 -13
- data/lib/thrift/transport/unix_server_socket.rb +9 -5
- data/lib/thrift/transport/unix_socket.rb +7 -6
- data/lib/thrift/types.rb +10 -6
- data/lib/thrift/union.rb +15 -8
- data/lib/thrift/uuid.rb +50 -0
- data/lib/thrift.rb +4 -1
- data/spec/ThriftSpec.thrift +21 -1
- data/spec/base_protocol_spec.rb +21 -2
- data/spec/base_transport_spec.rb +48 -8
- data/spec/binary_protocol_accelerated_spec.rb +1 -0
- data/spec/binary_protocol_spec.rb +1 -2
- data/spec/binary_protocol_spec_shared.rb +206 -155
- data/spec/bytes_spec.rb +71 -114
- data/spec/client_spec.rb +86 -19
- data/spec/compact_protocol_spec.rb +153 -16
- data/spec/constants_demo_spec.rb +102 -0
- data/spec/exception_spec.rb +1 -1
- data/spec/flat_spec.rb +1 -0
- data/spec/header_protocol_spec.rb +476 -0
- data/spec/header_transport_spec.rb +431 -0
- data/spec/http_client_spec.rb +5 -6
- data/spec/json_protocol_spec.rb +69 -47
- data/spec/multiplexed_processor_spec.rb +75 -0
- data/spec/namespaced_spec.rb +1 -1
- data/spec/nonblocking_server_spec.rb +174 -8
- data/spec/processor_spec.rb +1 -1
- data/spec/recursion_depth_spec.rb +223 -0
- data/spec/serializer_spec.rb +1 -1
- data/spec/server_socket_spec.rb +38 -1
- data/spec/server_spec.rb +60 -9
- data/spec/socket_spec.rb +119 -13
- data/spec/socket_spec_shared.rb +73 -9
- data/spec/spec_helper.rb +2 -1
- data/spec/ssl_server_socket_spec.rb +52 -1
- data/spec/ssl_socket_spec.rb +181 -11
- data/spec/struct_nested_containers_spec.rb +2 -2
- data/spec/struct_spec.rb +114 -9
- data/spec/support/header_protocol_helper.rb +55 -0
- data/spec/thin_http_server_spec.rb +4 -18
- data/spec/types_spec.rb +26 -26
- data/spec/union_spec.rb +70 -11
- data/spec/unix_socket_spec.rb +17 -2
- data/spec/uuid_validation_spec.rb +239 -0
- data/test/fuzz/Makefile +779 -0
- data/test/fuzz/Makefile.am +173 -0
- data/test/fuzz/Makefile.in +775 -0
- data/test/fuzz/README.md +149 -0
- data/test/fuzz/fuzz_common.rb +96 -0
- data/{lib/thrift/core_ext.rb → test/fuzz/fuzz_parse_binary_protocol.rb} +4 -4
- data/{lib/thrift/core_ext/fixnum.rb → test/fuzz/fuzz_parse_binary_protocol_accelerated.rb} +7 -13
- data/test/fuzz/fuzz_parse_binary_protocol_accelerated_harness.rb +23 -0
- data/test/fuzz/fuzz_parse_binary_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_parse_compact_protocol.rb +23 -0
- data/test/fuzz/fuzz_parse_compact_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_parse_json_protocol.rb +23 -0
- data/test/fuzz/fuzz_parse_json_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_accelerated_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_binary_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_compact_protocol.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_compact_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_json_protocol.rb +23 -0
- data/test/fuzz/fuzz_roundtrip_json_protocol_harness.rb +23 -0
- data/test/fuzz/fuzz_tracer.rb +29 -0
- metadata +105 -70
data/spec/socket_spec_shared.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
|
|
@@ -67,38 +68,101 @@ shared_examples_for "a socket" do
|
|
|
67
68
|
@socket.open
|
|
68
69
|
allow(@handle).to receive(:closed?).and_return(true)
|
|
69
70
|
expect(@socket).not_to be_open
|
|
70
|
-
expect { @socket.write("fail") }.to raise_error(
|
|
71
|
-
expect { @socket.read(10) }.to raise_error(
|
|
71
|
+
expect { @socket.write("fail") }.to raise_error(Thrift::TransportException, "closed stream") { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) }
|
|
72
|
+
expect { @socket.read(10) }.to raise_error(Thrift::TransportException, "closed stream") { |e| expect(e.type).to eq(Thrift::TransportException::NOT_OPEN) }
|
|
72
73
|
end
|
|
73
74
|
|
|
74
75
|
it "should support the timeout accessor for read" do
|
|
75
76
|
@socket.timeout = 3
|
|
76
77
|
@socket.open
|
|
77
|
-
expect(
|
|
78
|
-
expect(
|
|
78
|
+
expect(@handle).to receive(:read_nonblock).with(17).and_raise(IO::EAGAINWaitReadable)
|
|
79
|
+
expect(IO).to receive(:select) do |rd, wr, err, timeout|
|
|
80
|
+
expect(rd).to eq([@handle])
|
|
81
|
+
expect(wr).to be_nil
|
|
82
|
+
expect(err).to be_nil
|
|
83
|
+
expect(timeout).to be > 0
|
|
84
|
+
expect(timeout).to be <= 3
|
|
85
|
+
[[@handle], [], []]
|
|
86
|
+
end
|
|
87
|
+
expect(@handle).to receive(:read_nonblock).with(17).and_return("test data")
|
|
79
88
|
expect(@socket.read(17)).to eq("test data")
|
|
80
89
|
end
|
|
81
90
|
|
|
82
91
|
it "should support the timeout accessor for write" do
|
|
83
92
|
@socket.timeout = 3
|
|
84
93
|
@socket.open
|
|
85
|
-
|
|
86
|
-
expect(@handle).to receive(:write_nonblock).
|
|
87
|
-
|
|
94
|
+
write_calls = 0
|
|
95
|
+
expect(@handle).to receive(:write_nonblock).exactly(3).times do |chunk|
|
|
96
|
+
write_calls += 1
|
|
97
|
+
case write_calls
|
|
98
|
+
when 1
|
|
99
|
+
expect(chunk).to eq("test data")
|
|
100
|
+
raise IO::EAGAINWaitWritable
|
|
101
|
+
when 2
|
|
102
|
+
expect(chunk).to eq("test data")
|
|
103
|
+
4
|
|
104
|
+
when 3
|
|
105
|
+
expect(chunk).to eq(" data")
|
|
106
|
+
5
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
expect(IO).to receive(:select) do |rd, wr, err, timeout|
|
|
110
|
+
expect(rd).to be_nil
|
|
111
|
+
expect(wr).to eq([@handle])
|
|
112
|
+
expect(err).to be_nil
|
|
113
|
+
expect(timeout).to be > 0
|
|
114
|
+
expect(timeout).to be <= 3
|
|
115
|
+
[[], [@handle], []]
|
|
116
|
+
end
|
|
88
117
|
expect(@socket.write("test data")).to eq(9)
|
|
89
118
|
end
|
|
90
119
|
|
|
91
120
|
it "should raise an error when read times out" do
|
|
92
121
|
@socket.timeout = 0.5
|
|
93
122
|
@socket.open
|
|
94
|
-
expect(
|
|
123
|
+
expect(@handle).to receive(:read_nonblock).with(17).and_raise(IO::EAGAINWaitReadable)
|
|
124
|
+
expect(IO).to receive(:select).once { sleep(0.6); nil }
|
|
95
125
|
expect { @socket.read(17) }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::TIMED_OUT) }
|
|
96
126
|
end
|
|
97
127
|
|
|
98
128
|
it "should raise an error when write times out" do
|
|
99
129
|
@socket.timeout = 0.5
|
|
100
130
|
@socket.open
|
|
101
|
-
|
|
131
|
+
expect(@handle).to receive(:write_nonblock).with("test data").and_raise(IO::EAGAINWaitWritable)
|
|
132
|
+
expect(IO).to receive(:select).once { sleep(0.6); nil }
|
|
102
133
|
expect { @socket.write("test data") }.to raise_error(Thrift::TransportException) { |e| expect(e.type).to eq(Thrift::TransportException::TIMED_OUT) }
|
|
103
134
|
end
|
|
135
|
+
|
|
136
|
+
it "should read buffered SSL data without waiting on the raw socket again" do
|
|
137
|
+
@socket.timeout = 1
|
|
138
|
+
@socket.open
|
|
139
|
+
|
|
140
|
+
expect(@handle).to receive(:read_nonblock).with(4).ordered.and_raise(IO::EAGAINWaitReadable)
|
|
141
|
+
expect(IO).to receive(:select).once.ordered do |rd, wr, err, timeout|
|
|
142
|
+
expect(rd).to eq([@handle])
|
|
143
|
+
expect(wr).to be_nil
|
|
144
|
+
expect(err).to be_nil
|
|
145
|
+
expect(timeout).to be > 0
|
|
146
|
+
expect(timeout).to be <= 1
|
|
147
|
+
[[@handle], [], []]
|
|
148
|
+
end
|
|
149
|
+
expect(@handle).to receive(:read_nonblock).with(4).ordered.and_return("ABCD")
|
|
150
|
+
expect(@handle).to receive(:read_nonblock).with(5).ordered.and_return("12345")
|
|
151
|
+
|
|
152
|
+
expect(@socket.read(4)).to eq("ABCD")
|
|
153
|
+
expect(@socket.read(5)).to eq("12345")
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it "should read without timeout using the blocking path" do
|
|
157
|
+
@socket.timeout = nil
|
|
158
|
+
@socket.open
|
|
159
|
+
|
|
160
|
+
expect(IO).not_to receive(:select)
|
|
161
|
+
expect(@handle).not_to receive(:read_nonblock)
|
|
162
|
+
expect(@handle).to receive(:readpartial).with(4).ordered.and_return("ABCD")
|
|
163
|
+
expect(@handle).to receive(:readpartial).with(5).ordered.and_return("12345")
|
|
164
|
+
|
|
165
|
+
expect(@socket.read(4)).to eq("ABCD")
|
|
166
|
+
expect(@socket.read(5)).to eq("12345")
|
|
167
|
+
end
|
|
104
168
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: UTF-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
#
|
|
3
4
|
# Licensed to the Apache Software Foundation (ASF) under one
|
|
4
5
|
# or more contributor license agreements. See the NOTICE file
|
|
@@ -55,7 +56,7 @@ require 'nonblocking_service'
|
|
|
55
56
|
|
|
56
57
|
module Fixtures
|
|
57
58
|
COMPACT_PROTOCOL_TEST_STRUCT = Thrift::Test::COMPACT_TEST.dup
|
|
58
|
-
COMPACT_PROTOCOL_TEST_STRUCT.a_binary = [0,1,2,3,4,5,6,7,8].pack('c*')
|
|
59
|
+
COMPACT_PROTOCOL_TEST_STRUCT.a_binary = [0, 1, 2, 3, 4, 5, 6, 7, 8].pack('c*')
|
|
59
60
|
COMPACT_PROTOCOL_TEST_STRUCT.set_byte_map = nil
|
|
60
61
|
COMPACT_PROTOCOL_TEST_STRUCT.map_byte_map = nil
|
|
61
62
|
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
|
|
@@ -21,12 +22,62 @@ require 'spec_helper'
|
|
|
21
22
|
require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared")
|
|
22
23
|
|
|
23
24
|
describe 'SSLServerSocket' do
|
|
24
|
-
|
|
25
25
|
describe Thrift::SSLServerSocket do
|
|
26
26
|
before(:each) do
|
|
27
27
|
@socket = Thrift::SSLServerSocket.new(1234)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
it "should delegate to_io to the underlying SSL server handle" do
|
|
31
|
+
tcp_server = double("TCPServer")
|
|
32
|
+
ssl_server = double("SSLServer")
|
|
33
|
+
|
|
34
|
+
allow(TCPServer).to receive(:new).with(nil, 1234).and_return(tcp_server)
|
|
35
|
+
allow(OpenSSL::SSL::SSLServer).to receive(:new).with(tcp_server, nil).and_return(ssl_server)
|
|
36
|
+
allow(ssl_server).to receive(:to_io).and_return(tcp_server)
|
|
37
|
+
|
|
38
|
+
@socket.listen
|
|
39
|
+
expect(@socket.to_io).to eq(tcp_server)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should default accepted sockets to a finite client timeout" do
|
|
43
|
+
expect(@socket.client_timeout).to eq(5)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should preserve the positional ssl context argument" do
|
|
47
|
+
context = double("SSLContext")
|
|
48
|
+
socket = Thrift::SSLServerSocket.new(nil, 1234, context)
|
|
49
|
+
|
|
50
|
+
expect(socket.ssl_context).to eq(context)
|
|
51
|
+
expect(socket.client_timeout).to eq(5)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should accept a custom client timeout" do
|
|
55
|
+
context = double("SSLContext")
|
|
56
|
+
socket = Thrift::SSLServerSocket.new(nil, 1234, context, client_timeout: 2.5)
|
|
57
|
+
|
|
58
|
+
expect(socket.ssl_context).to eq(context)
|
|
59
|
+
expect(socket.client_timeout).to eq(2.5)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "should apply the client timeout to accepted sockets" do
|
|
63
|
+
tcp_server = double("TCPServer")
|
|
64
|
+
ssl_server = double("SSLServer")
|
|
65
|
+
sock = double("SSLSocket")
|
|
66
|
+
|
|
67
|
+
allow(TCPServer).to receive(:new).with(nil, 1234).and_return(tcp_server)
|
|
68
|
+
allow(OpenSSL::SSL::SSLServer).to receive(:new).with(tcp_server, nil).and_return(ssl_server)
|
|
69
|
+
expect(ssl_server).to receive(:accept).and_return(sock)
|
|
70
|
+
expect(sock).to receive(:setsockopt).with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
|
71
|
+
|
|
72
|
+
trans = double("Socket")
|
|
73
|
+
expect(Thrift::Socket).to receive(:new).and_return(trans)
|
|
74
|
+
expect(trans).to receive(:timeout=).with(Thrift::BaseServerTransport::DEFAULT_CLIENT_TIMEOUT)
|
|
75
|
+
expect(trans).to receive(:handle=).with(sock)
|
|
76
|
+
|
|
77
|
+
@socket.listen
|
|
78
|
+
expect(@socket.accept).to eq(trans)
|
|
79
|
+
end
|
|
80
|
+
|
|
30
81
|
it "should provide a reasonable to_s" do
|
|
31
82
|
expect(@socket.to_s).to eq("ssl(socket(:1234))")
|
|
32
83
|
end
|
data/spec/ssl_socket_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
|
|
@@ -21,44 +22,60 @@ require 'spec_helper'
|
|
|
21
22
|
require File.expand_path("#{File.dirname(__FILE__)}/socket_spec_shared")
|
|
22
23
|
|
|
23
24
|
describe 'SSLSocket' do
|
|
24
|
-
|
|
25
25
|
describe Thrift::SSLSocket do
|
|
26
26
|
before(:each) do
|
|
27
27
|
@context = OpenSSL::SSL::SSLContext.new
|
|
28
28
|
@socket = Thrift::SSLSocket.new
|
|
29
|
+
@addrinfo = double("Addrinfo")
|
|
29
30
|
@simple_socket_handle = double("Handle", :closed? => false)
|
|
30
31
|
allow(@simple_socket_handle).to receive(:close)
|
|
31
|
-
allow(@simple_socket_handle).to receive(:connect_nonblock)
|
|
32
32
|
allow(@simple_socket_handle).to receive(:setsockopt)
|
|
33
|
+
allow(@simple_socket_handle).to receive(:wait_readable)
|
|
34
|
+
allow(@simple_socket_handle).to receive(:wait_writable)
|
|
33
35
|
|
|
34
|
-
@handle = double(
|
|
35
|
-
allow(@handle).to receive(:
|
|
36
|
+
@handle = double("SSLHandle", :closed? => false)
|
|
37
|
+
allow(@handle).to receive(:connect).and_return(true)
|
|
38
|
+
allow(@handle).to receive(:connect_nonblock).and_return(@handle)
|
|
36
39
|
allow(@handle).to receive(:close)
|
|
37
40
|
allow(@handle).to receive(:post_connection_check)
|
|
41
|
+
allow(@handle).to receive(:sync_close=)
|
|
42
|
+
allow(@handle).to receive(:to_io).and_return(@simple_socket_handle)
|
|
38
43
|
|
|
39
|
-
allow(
|
|
44
|
+
allow(@addrinfo).to receive(:connect).and_return(@simple_socket_handle)
|
|
45
|
+
allow(Addrinfo).to receive(:foreach).and_yield(@addrinfo)
|
|
40
46
|
allow(OpenSSL::SSL::SSLSocket).to receive(:new).and_return(@handle)
|
|
41
47
|
end
|
|
42
48
|
|
|
43
49
|
it_should_behave_like "a socket"
|
|
44
50
|
|
|
45
51
|
it "should raise a TransportException when it cannot open a ssl socket" do
|
|
46
|
-
|
|
47
|
-
expect { @socket.open }.to raise_error(Thrift::TransportException)
|
|
52
|
+
allow(Addrinfo).to receive(:foreach).and_raise(SocketError.new("lookup failed"))
|
|
53
|
+
expect { @socket.open }.to raise_error(Thrift::TransportException) do |e|
|
|
54
|
+
expect(e.type).to eq(Thrift::TransportException::NOT_OPEN)
|
|
55
|
+
expect(e.message).to eq("Could not connect to localhost:9090")
|
|
56
|
+
expect(e.cause).to be_a(SocketError)
|
|
57
|
+
end
|
|
48
58
|
end
|
|
49
59
|
|
|
50
60
|
it "should open a ::Socket with default args" do
|
|
61
|
+
expect(@simple_socket_handle).to receive(:setsockopt).with(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
|
51
62
|
expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(@simple_socket_handle, nil).and_return(@handle)
|
|
63
|
+
expect(@handle).to receive(:sync_close=).with(true)
|
|
64
|
+
expect(@handle).to receive(:connect).and_return(true)
|
|
52
65
|
expect(@handle).to receive(:post_connection_check).with('localhost')
|
|
53
66
|
@socket.open
|
|
54
67
|
end
|
|
55
68
|
|
|
56
69
|
it "should accept host/port options" do
|
|
57
|
-
handle = double("Handle", :
|
|
58
|
-
allow(
|
|
59
|
-
expect(
|
|
60
|
-
expect(
|
|
70
|
+
handle = double("Handle", :closed? => false)
|
|
71
|
+
allow(handle).to receive(:close)
|
|
72
|
+
expect(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC).and_return(100.0, 100.0)
|
|
73
|
+
expect(handle).to receive(:setsockopt).with(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
|
74
|
+
expect(Addrinfo).to receive(:foreach).with("my.domain", 1234, nil, :STREAM).and_yield(@addrinfo)
|
|
75
|
+
expect(@addrinfo).to receive(:connect).with(timeout: 6000).and_return(handle)
|
|
61
76
|
expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(handle, nil).and_return(@handle)
|
|
77
|
+
expect(@handle).to receive(:sync_close=).with(true)
|
|
78
|
+
expect(@handle).to receive(:connect_nonblock).with(exception: false).and_return(@handle)
|
|
62
79
|
expect(@handle).to receive(:post_connection_check).with('my.domain')
|
|
63
80
|
Thrift::SSLSocket.new('my.domain', 1234, 6000, nil).open
|
|
64
81
|
end
|
|
@@ -71,6 +88,159 @@ describe 'SSLSocket' do
|
|
|
71
88
|
expect(Thrift::SSLSocket.new('localhost', 8080, 5, @context).ssl_context).to eq(@context)
|
|
72
89
|
end
|
|
73
90
|
|
|
91
|
+
it "should treat zero timeout as blocking for open and handshake" do
|
|
92
|
+
@socket.timeout = 0
|
|
93
|
+
|
|
94
|
+
expect(@addrinfo).to receive(:connect).with(no_args).and_return(@simple_socket_handle)
|
|
95
|
+
expect(@simple_socket_handle).to receive(:setsockopt).with(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
|
96
|
+
expect(@handle).to receive(:sync_close=).with(true)
|
|
97
|
+
expect(@handle).to receive(:connect).and_return(true)
|
|
98
|
+
expect(@handle).not_to receive(:connect_nonblock)
|
|
99
|
+
expect(@handle).to receive(:post_connection_check).with('localhost')
|
|
100
|
+
|
|
101
|
+
expect(@socket.open).to eq(@handle)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "should use the remaining timeout across ssl wait states" do
|
|
105
|
+
@socket.timeout = 5
|
|
106
|
+
|
|
107
|
+
expect(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC).and_return(100.0, 101.0, 102.0, 104.0)
|
|
108
|
+
expect(@addrinfo).to receive(:connect).with(timeout: 4.0).and_return(@simple_socket_handle)
|
|
109
|
+
expect(@simple_socket_handle).to receive(:setsockopt).with(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
|
110
|
+
expect(@handle).to receive(:sync_close=).with(true)
|
|
111
|
+
expect(@handle).to receive(:connect_nonblock).with(exception: false).ordered.and_return(:wait_readable)
|
|
112
|
+
expect(@simple_socket_handle).to receive(:wait_readable).with(3.0).ordered.and_return(true)
|
|
113
|
+
expect(@handle).to receive(:connect_nonblock).with(exception: false).ordered.and_return(:wait_writable)
|
|
114
|
+
expect(@simple_socket_handle).to receive(:wait_writable).with(1.0).ordered.and_return(true)
|
|
115
|
+
expect(@handle).to receive(:connect_nonblock).with(exception: false).ordered.and_return(@handle)
|
|
116
|
+
expect(@handle).to receive(:post_connection_check).with('localhost')
|
|
117
|
+
|
|
118
|
+
expect(@socket.open).to eq(@handle)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "should share one timeout budget across tcp fallback and the ssl handshake" do
|
|
122
|
+
@socket.timeout = 5
|
|
123
|
+
second_addrinfo = double("Addrinfo")
|
|
124
|
+
|
|
125
|
+
expect(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC).and_return(100.0, 101.0, 102.0, 103.0)
|
|
126
|
+
expect(Addrinfo).to receive(:foreach).with("localhost", 9090, nil, :STREAM).and_yield(@addrinfo).and_yield(second_addrinfo)
|
|
127
|
+
expect(@addrinfo).to receive(:connect).with(timeout: 4.0).and_raise(Errno::ECONNREFUSED)
|
|
128
|
+
expect(second_addrinfo).to receive(:connect).with(timeout: 3.0).and_return(@simple_socket_handle)
|
|
129
|
+
expect(@simple_socket_handle).to receive(:setsockopt).with(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
|
130
|
+
expect(@handle).to receive(:sync_close=).with(true)
|
|
131
|
+
expect(@handle).to receive(:connect_nonblock).with(exception: false).ordered.and_return(:wait_readable)
|
|
132
|
+
expect(@simple_socket_handle).to receive(:wait_readable).with(2.0).ordered.and_return(true)
|
|
133
|
+
expect(@handle).to receive(:connect_nonblock).with(exception: false).ordered.and_return(@handle)
|
|
134
|
+
expect(@handle).to receive(:post_connection_check).with('localhost')
|
|
135
|
+
|
|
136
|
+
expect(@socket.open).to eq(@handle)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "should continue to the next address after a tcp connect timeout during ssl open" do
|
|
140
|
+
@socket.timeout = 5
|
|
141
|
+
second_addrinfo = double("Addrinfo")
|
|
142
|
+
|
|
143
|
+
expect(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC).and_return(100.0, 101.0, 103.0)
|
|
144
|
+
expect(Addrinfo).to receive(:foreach).with("localhost", 9090, nil, :STREAM).and_yield(@addrinfo).and_yield(second_addrinfo)
|
|
145
|
+
expect(@addrinfo).to receive(:connect).with(timeout: 4.0).and_raise(Errno::ETIMEDOUT)
|
|
146
|
+
expect(second_addrinfo).to receive(:connect).with(timeout: 2.0).and_return(@simple_socket_handle)
|
|
147
|
+
expect(@simple_socket_handle).to receive(:setsockopt).with(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
|
148
|
+
expect(@handle).to receive(:sync_close=).with(true)
|
|
149
|
+
expect(@handle).to receive(:connect_nonblock).with(exception: false).and_return(@handle)
|
|
150
|
+
expect(@handle).to receive(:post_connection_check).with('localhost')
|
|
151
|
+
|
|
152
|
+
expect(@socket.open).to eq(@handle)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "should raise TIMED_OUT when ssl handshake wait times out" do
|
|
156
|
+
@socket.timeout = 5
|
|
157
|
+
|
|
158
|
+
expect(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC).and_return(100.0, 101.0, 102.0)
|
|
159
|
+
expect(@addrinfo).to receive(:connect).with(timeout: 4.0).and_return(@simple_socket_handle)
|
|
160
|
+
expect(@simple_socket_handle).to receive(:setsockopt).with(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
|
161
|
+
expect(@handle).to receive(:sync_close=).with(true)
|
|
162
|
+
expect(@handle).to receive(:connect_nonblock).with(exception: false).and_return(:wait_readable)
|
|
163
|
+
expect(@simple_socket_handle).to receive(:wait_readable).with(3.0).and_return(nil)
|
|
164
|
+
expect(@handle).to receive(:close)
|
|
165
|
+
|
|
166
|
+
expect { @socket.open }.to raise_error(Thrift::TransportException) do |e|
|
|
167
|
+
expect(e.type).to eq(Thrift::TransportException::TIMED_OUT)
|
|
168
|
+
expect(e.message).to eq("SSL socket: Timed out establishing session with localhost:9090")
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "should surface tcp open timeout before starting ssl" do
|
|
173
|
+
@socket.timeout = 5
|
|
174
|
+
|
|
175
|
+
expect(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC).and_return(100.0, 101.0)
|
|
176
|
+
expect(@addrinfo).to receive(:connect).with(timeout: 4.0).and_raise(Errno::ETIMEDOUT)
|
|
177
|
+
expect(OpenSSL::SSL::SSLSocket).not_to receive(:new)
|
|
178
|
+
|
|
179
|
+
expect { @socket.open }.to raise_error(Thrift::TransportException) do |e|
|
|
180
|
+
expect(e.type).to eq(Thrift::TransportException::TIMED_OUT)
|
|
181
|
+
expect(e.message).to eq("Socket: Timed out opening connection to localhost:9090")
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it "should close the raw socket if ssl wrapper creation fails" do
|
|
186
|
+
@socket.timeout = 5
|
|
187
|
+
|
|
188
|
+
expect(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC).and_return(100.0, 101.0)
|
|
189
|
+
expect(@addrinfo).to receive(:connect).with(timeout: 4.0).and_return(@simple_socket_handle)
|
|
190
|
+
expect(@simple_socket_handle).to receive(:setsockopt).with(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
|
191
|
+
expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(@simple_socket_handle, nil).and_raise(StandardError.new("ssl init failed"))
|
|
192
|
+
expect(@simple_socket_handle).to receive(:close)
|
|
193
|
+
|
|
194
|
+
expect { @socket.open }.to raise_error(Thrift::TransportException) do |e|
|
|
195
|
+
expect(e.type).to eq(Thrift::TransportException::NOT_OPEN)
|
|
196
|
+
expect(e.message).to eq("Could not connect to localhost:9090")
|
|
197
|
+
expect(e.cause.message).to eq("ssl init failed")
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it "should close the ssl socket when post connection check fails" do
|
|
202
|
+
@socket.timeout = 5
|
|
203
|
+
|
|
204
|
+
expect(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC).and_return(100.0, 101.0)
|
|
205
|
+
expect(@addrinfo).to receive(:connect).with(timeout: 4.0).and_return(@simple_socket_handle)
|
|
206
|
+
expect(@simple_socket_handle).to receive(:setsockopt).with(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
|
207
|
+
expect(@handle).to receive(:sync_close=).with(true)
|
|
208
|
+
expect(@handle).to receive(:connect_nonblock).with(exception: false).and_return(@handle)
|
|
209
|
+
expect(@handle).to receive(:post_connection_check).with('localhost').and_raise(StandardError.new("hostname mismatch"))
|
|
210
|
+
expect(@handle).to receive(:close)
|
|
211
|
+
|
|
212
|
+
expect { @socket.open }.to raise_error(Thrift::TransportException) do |e|
|
|
213
|
+
expect(e.type).to eq(Thrift::TransportException::NOT_OPEN)
|
|
214
|
+
expect(e.message).to eq("Could not connect to localhost:9090")
|
|
215
|
+
expect(e.cause.message).to eq("hostname mismatch")
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
it "should close the ssl socket on an unexpected nonblocking handshake result" do
|
|
220
|
+
@socket.timeout = 5
|
|
221
|
+
|
|
222
|
+
expect(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC).and_return(100.0, 101.0)
|
|
223
|
+
expect(@addrinfo).to receive(:connect).with(timeout: 4.0).and_return(@simple_socket_handle)
|
|
224
|
+
expect(@simple_socket_handle).to receive(:setsockopt).with(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
|
225
|
+
expect(@handle).to receive(:sync_close=).with(true)
|
|
226
|
+
expect(@handle).to receive(:connect_nonblock).with(exception: false).and_return(:unexpected)
|
|
227
|
+
expect(@handle).to receive(:close)
|
|
228
|
+
|
|
229
|
+
expect { @socket.open }.to raise_error(Thrift::TransportException) do |e|
|
|
230
|
+
expect(e.type).to eq(Thrift::TransportException::NOT_OPEN)
|
|
231
|
+
expect(e.message).to include("unexpected SSL connect result")
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
it "should delegate to_io to the underlying SSL socket handle" do
|
|
236
|
+
@socket.open
|
|
237
|
+
expect(@socket.to_io).to eq(@simple_socket_handle)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
it "should raise IOError when to_io is called on a closed stream" do
|
|
241
|
+
expect { @socket.to_io }.to raise_error(IOError, 'closed stream')
|
|
242
|
+
end
|
|
243
|
+
|
|
74
244
|
it "should provide a reasonable to_s" do
|
|
75
245
|
expect(Thrift::SSLSocket.new('myhost', 8090).to_s).to eq("ssl(socket(myhost:8090))")
|
|
76
246
|
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 'StructNestedContainers' do
|
|
23
|
-
|
|
24
24
|
def with_type_checking
|
|
25
25
|
saved_type_checking, Thrift.type_checking = Thrift.type_checking, true
|
|
26
26
|
begin
|
|
@@ -166,7 +166,7 @@ describe 'StructNestedContainers' do
|
|
|
166
166
|
with_type_checking do
|
|
167
167
|
a, b = SpecNamespace::NestedMapInMapKey.new, SpecNamespace::NestedMapInMapKey.new
|
|
168
168
|
[a, b].each do |thrift_struct|
|
|
169
|
-
thrift_struct.value = { { 1 => 2, 3 => 4} => 1, {2 => 3, 4 => 5}
|
|
169
|
+
thrift_struct.value = { { 1 => 2, 3 => 4} => 1, {2 => 3, 4 => 5} => 2 }
|
|
170
170
|
thrift_struct.validate
|
|
171
171
|
end
|
|
172
172
|
expect(a).to eq(b)
|
data/spec/struct_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
|
|
@@ -20,11 +21,10 @@
|
|
|
20
21
|
require 'spec_helper'
|
|
21
22
|
|
|
22
23
|
describe 'Struct' do
|
|
23
|
-
|
|
24
24
|
describe Thrift::Struct do
|
|
25
25
|
it "should iterate over all fields properly" do
|
|
26
26
|
fields = {}
|
|
27
|
-
SpecNamespace::Foo.new.each_field { |fid,field_info| fields[fid] = field_info }
|
|
27
|
+
SpecNamespace::Foo.new.each_field { |fid, field_info| fields[fid] = field_info }
|
|
28
28
|
expect(fields).to eq(SpecNamespace::Foo::FIELDS)
|
|
29
29
|
end
|
|
30
30
|
|
|
@@ -51,10 +51,10 @@ describe 'Struct' do
|
|
|
51
51
|
begin
|
|
52
52
|
struct = SpecNamespace::Foo.new
|
|
53
53
|
struct.ints << 17
|
|
54
|
-
expect(SpecNamespace::Foo.new.ints).to eq([1,2,2,3])
|
|
54
|
+
expect(SpecNamespace::Foo.new.ints).to eq([1, 2, 2, 3])
|
|
55
55
|
ensure
|
|
56
56
|
# ensure no leakage to other tests
|
|
57
|
-
SpecNamespace::Foo::FIELDS[4][:default] = [1,2,2,3]
|
|
57
|
+
SpecNamespace::Foo::FIELDS[4][:default] = [1, 2, 2, 3]
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
@@ -142,6 +142,34 @@ describe 'Struct' do
|
|
|
142
142
|
expect(struct.shorts).to eq(Set.new([3, 2]))
|
|
143
143
|
end
|
|
144
144
|
|
|
145
|
+
it "rejects negative container sizes while reading" do
|
|
146
|
+
struct = SpecNamespace::Foo.new
|
|
147
|
+
prot = Thrift::BaseProtocol.new(double("transport"))
|
|
148
|
+
|
|
149
|
+
expect(prot).to receive(:read_list_begin).and_return([Thrift::Types::I32, -1])
|
|
150
|
+
|
|
151
|
+
expect {
|
|
152
|
+
struct.send(:read_field, prot, SpecNamespace::Foo::FIELDS[4])
|
|
153
|
+
}.to raise_error(Thrift::ProtocolException, "Negative size") { |error|
|
|
154
|
+
expect(error.type).to eq(Thrift::ProtocolException::NEGATIVE_SIZE)
|
|
155
|
+
}
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it "does not preallocate arrays from declared list sizes" do
|
|
159
|
+
struct = SpecNamespace::Foo.new
|
|
160
|
+
prot = Thrift::BaseProtocol.new(double("transport"))
|
|
161
|
+
declared_size = 1 << 30
|
|
162
|
+
sentinel = RuntimeError.new("stop after first element")
|
|
163
|
+
|
|
164
|
+
expect(prot).to receive(:read_list_begin).and_return([Thrift::Types::I32, declared_size])
|
|
165
|
+
expect(prot).to receive(:read_i32).and_raise(sentinel)
|
|
166
|
+
expect(Array).not_to receive(:new).with(declared_size)
|
|
167
|
+
|
|
168
|
+
expect {
|
|
169
|
+
struct.send(:read_field, prot, SpecNamespace::Foo::FIELDS[4])
|
|
170
|
+
}.to raise_error(sentinel)
|
|
171
|
+
end
|
|
172
|
+
|
|
145
173
|
it "should serialize false boolean fields correctly" do
|
|
146
174
|
b = SpecNamespace::BoolStruct.new(:yesno => false)
|
|
147
175
|
prot = Thrift::BinaryProtocol.new(Thrift::MemoryBufferTransport.new)
|
|
@@ -181,7 +209,7 @@ describe 'Struct' do
|
|
|
181
209
|
end
|
|
182
210
|
|
|
183
211
|
it "should write itself to the wire" do
|
|
184
|
-
prot = Thrift::BaseProtocol.new(double("transport")) #mock("Protocol")
|
|
212
|
+
prot = Thrift::BaseProtocol.new(double("transport")) # mock("Protocol")
|
|
185
213
|
expect(prot).to receive(:write_struct_begin).with("SpecNamespace::Foo")
|
|
186
214
|
expect(prot).to receive(:write_struct_begin).with("SpecNamespace::Hello")
|
|
187
215
|
expect(prot).to receive(:write_struct_end).twice
|
|
@@ -227,7 +255,7 @@ describe 'Struct' do
|
|
|
227
255
|
it "should support optional type-checking in Thrift::Struct.new" do
|
|
228
256
|
Thrift.type_checking = true
|
|
229
257
|
begin
|
|
230
|
-
expect { SpecNamespace::Hello.new(:greeting => 3) }.to raise_error(Thrift::TypeError,
|
|
258
|
+
expect { SpecNamespace::Hello.new(:greeting => 3) }.to raise_error(Thrift::TypeError, "Expected Types::STRING, received Integer for field greeting")
|
|
231
259
|
ensure
|
|
232
260
|
Thrift.type_checking = false
|
|
233
261
|
end
|
|
@@ -238,7 +266,7 @@ describe 'Struct' do
|
|
|
238
266
|
Thrift.type_checking = true
|
|
239
267
|
begin
|
|
240
268
|
hello = SpecNamespace::Hello.new
|
|
241
|
-
expect { hello.greeting = 3 }.to raise_error(Thrift::TypeError,
|
|
269
|
+
expect { hello.greeting = 3 }.to raise_error(Thrift::TypeError, "Expected Types::STRING, received Integer for field greeting")
|
|
242
270
|
ensure
|
|
243
271
|
Thrift.type_checking = false
|
|
244
272
|
end
|
|
@@ -259,9 +287,9 @@ describe 'Struct' do
|
|
|
259
287
|
prot = Thrift::BaseProtocol.new(double("trans"))
|
|
260
288
|
expect(prot).to receive(:write_struct_begin).with("SpecNamespace::Xception")
|
|
261
289
|
expect(prot).to receive(:write_struct_end)
|
|
262
|
-
expect(prot).to receive(:write_field_begin).with('message', Thrift::Types::STRING, 1)
|
|
290
|
+
expect(prot).to receive(:write_field_begin).with('message', Thrift::Types::STRING, 1)
|
|
263
291
|
expect(prot).to receive(:write_string).with("something happened")
|
|
264
|
-
expect(prot).to receive(:write_field_begin).with('code', Thrift::Types::I32, 2)
|
|
292
|
+
expect(prot).to receive(:write_field_begin).with('code', Thrift::Types::I32, 2)
|
|
265
293
|
expect(prot).to receive(:write_i32).with(1)
|
|
266
294
|
expect(prot).to receive(:write_field_stop)
|
|
267
295
|
expect(prot).to receive(:write_field_end).twice
|
|
@@ -289,5 +317,82 @@ describe 'Struct' do
|
|
|
289
317
|
e.write(prot)
|
|
290
318
|
end
|
|
291
319
|
end
|
|
320
|
+
|
|
321
|
+
it "should handle UUID fields in structs" do
|
|
322
|
+
struct = SpecNamespace::Foo.new(
|
|
323
|
+
simple: 42,
|
|
324
|
+
words: 'test',
|
|
325
|
+
opt_uuid: '550e8400-e29b-41d4-a716-446655440000'
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
trans = Thrift::MemoryBufferTransport.new
|
|
329
|
+
prot = Thrift::BinaryProtocol.new(trans)
|
|
330
|
+
|
|
331
|
+
struct.write(prot)
|
|
332
|
+
|
|
333
|
+
result = SpecNamespace::Foo.new
|
|
334
|
+
result.read(prot)
|
|
335
|
+
|
|
336
|
+
expect(result.simple).to eq(42)
|
|
337
|
+
expect(result.words).to eq('test')
|
|
338
|
+
expect(result.opt_uuid).to eq('550e8400-e29b-41d4-a716-446655440000')
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
it "should handle optional UUID fields when unset" do
|
|
342
|
+
struct = SpecNamespace::Foo.new(simple: 42, words: 'test')
|
|
343
|
+
expect(struct.opt_uuid).to be_nil
|
|
344
|
+
expect(struct.opt_uuid?).to be_falsey
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
it "should handle list of UUIDs in SimpleList" do
|
|
348
|
+
uuids = ['550e8400-e29b-41d4-a716-446655440000', '6ba7b810-9dad-11d1-80b4-00c04fd430c8']
|
|
349
|
+
struct = SpecNamespace::SimpleList.new(uuids: uuids)
|
|
350
|
+
|
|
351
|
+
trans = Thrift::MemoryBufferTransport.new
|
|
352
|
+
prot = Thrift::CompactProtocol.new(trans)
|
|
353
|
+
|
|
354
|
+
struct.write(prot)
|
|
355
|
+
|
|
356
|
+
result = SpecNamespace::SimpleList.new
|
|
357
|
+
result.read(prot)
|
|
358
|
+
|
|
359
|
+
expect(result.uuids).to eq(uuids)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
it "should normalize UUID case to lowercase" do
|
|
363
|
+
struct = SpecNamespace::Foo.new(opt_uuid: '550E8400-E29B-41D4-A716-446655440000')
|
|
364
|
+
|
|
365
|
+
trans = Thrift::MemoryBufferTransport.new
|
|
366
|
+
prot = Thrift::BinaryProtocol.new(trans)
|
|
367
|
+
|
|
368
|
+
struct.write(prot)
|
|
369
|
+
|
|
370
|
+
result = SpecNamespace::Foo.new
|
|
371
|
+
result.read(prot)
|
|
372
|
+
|
|
373
|
+
expect(result.opt_uuid).to eq('550e8400-e29b-41d4-a716-446655440000')
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
it "should handle UUID alongside other types in SimpleList" do
|
|
377
|
+
struct = SpecNamespace::SimpleList.new(
|
|
378
|
+
bools: [true, false],
|
|
379
|
+
i32s: [1, 2, 3],
|
|
380
|
+
strings: ['hello', 'world'],
|
|
381
|
+
uuids: ['550e8400-e29b-41d4-a716-446655440000', '00000000-0000-0000-0000-000000000000']
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
trans = Thrift::MemoryBufferTransport.new
|
|
385
|
+
prot = Thrift::BinaryProtocol.new(trans)
|
|
386
|
+
|
|
387
|
+
struct.write(prot)
|
|
388
|
+
|
|
389
|
+
result = SpecNamespace::SimpleList.new
|
|
390
|
+
result.read(prot)
|
|
391
|
+
|
|
392
|
+
expect(result.bools).to eq([true, false])
|
|
393
|
+
expect(result.i32s).to eq([1, 2, 3])
|
|
394
|
+
expect(result.strings).to eq(['hello', 'world'])
|
|
395
|
+
expect(result.uuids).to eq(['550e8400-e29b-41d4-a716-446655440000', '00000000-0000-0000-0000-000000000000'])
|
|
396
|
+
end
|
|
292
397
|
end
|
|
293
398
|
end
|