stark 0.7.0 → 0.8.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.
- data/.travis.yml +10 -0
- data/History.txt +19 -0
- data/Manifest.txt +17 -3
- data/README.md +164 -0
- data/Rakefile +4 -1
- data/bin/stark +11 -3
- data/examples/README.md +114 -0
- data/examples/client.rb +13 -0
- data/examples/health.thrift +9 -0
- data/examples/server.rb +18 -0
- data/lib/stark.rb +16 -2
- data/lib/stark/ast.rb +5 -0
- data/lib/stark/client.rb +3 -67
- data/lib/stark/exception.rb +9 -9
- data/lib/stark/processor.rb +13 -52
- data/lib/stark/protocol_helpers.rb +161 -0
- data/lib/stark/raw_parser.rb +75 -14
- data/lib/stark/ruby.rb +267 -248
- data/lib/stark/struct.rb +37 -26
- data/lib/stark/thrift.kpeg +6 -4
- data/stark.gemspec +15 -15
- data/test/ThriftSpec.thrift +4 -0
- data/test/comments.thrift +15 -0
- data/test/leg.rb +0 -2
- data/test/parsing_error.thrift +5 -0
- data/test/properties.thrift +9 -0
- data/test/test_client.rb +116 -241
- data/test/test_coerce_strings.rb +187 -0
- data/test/test_helper.rb +113 -0
- data/test/test_marshal.rb +131 -0
- data/test/test_parser.rb +61 -0
- data/test/test_ruby.rb +148 -9
- data/test/test_server.rb +96 -212
- data/test/test_stark.rb +67 -0
- data/test/types.thrift +49 -0
- data/test/users.thrift +16 -0
- metadata +33 -15
- data/README.txt +0 -67
- data/lib/stark/converters.rb +0 -188
- data/lib/stark/field.rb +0 -27
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
|
|
3
|
+
require 'stark'
|
|
4
|
+
require 'thrift'
|
|
5
|
+
|
|
6
|
+
require 'test/test_helper'
|
|
7
|
+
|
|
8
|
+
class TestCoerceStrings1 < Test::Unit::TestCase
|
|
9
|
+
IDL = "test/ThriftSpec.thrift"
|
|
10
|
+
SERVICE = "SpecNamespace::NonblockingService"
|
|
11
|
+
include TestHelper
|
|
12
|
+
|
|
13
|
+
class Handler
|
|
14
|
+
def sleep_value
|
|
15
|
+
@sleep
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def sleep(sec)
|
|
19
|
+
@sleep = sec
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def setup
|
|
24
|
+
@handler = Handler.new
|
|
25
|
+
setup_server @handler
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_coerce_string_to_double
|
|
29
|
+
|
|
30
|
+
send_to_server do
|
|
31
|
+
name = "sleep"
|
|
32
|
+
@client_p.write_message_begin name, Thrift::MessageTypes::CALL, 0
|
|
33
|
+
@client_p.write_struct_begin "#{name}_args"
|
|
34
|
+
@client_p.write_field_begin "seconds", Thrift::Types::STRING, 1
|
|
35
|
+
@client_p.write_string "1.5"
|
|
36
|
+
@client_p.write_field_end
|
|
37
|
+
@client_p.write_field_stop
|
|
38
|
+
@client_p.write_struct_end
|
|
39
|
+
@client_p.write_message_end
|
|
40
|
+
@client_p.trans.flush
|
|
41
|
+
|
|
42
|
+
@client_p.read_message_begin
|
|
43
|
+
@client_p.skip Thrift::Types::STRUCT
|
|
44
|
+
@client_p.read_message_end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
assert_equal 1.5, @handler.sleep_value
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class TestCoerceStrings2 < Test::Unit::TestCase
|
|
52
|
+
IDL = "test/profile.thrift"
|
|
53
|
+
SERVICE = "UserStorage"
|
|
54
|
+
include TestHelper
|
|
55
|
+
|
|
56
|
+
def setup
|
|
57
|
+
setup_server
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_coerce_string_to_int
|
|
61
|
+
|
|
62
|
+
send_to_server do
|
|
63
|
+
name = "add"
|
|
64
|
+
@client_p.write_message_begin name, Thrift::MessageTypes::CALL, 0
|
|
65
|
+
@client_p.write_struct_begin "#{name}_args"
|
|
66
|
+
@client_p.write_field_begin "a", Thrift::Types::STRING, 1
|
|
67
|
+
@client_p.write_string "1"
|
|
68
|
+
@client_p.write_field_end
|
|
69
|
+
@client_p.write_field_begin "b", Thrift::Types::STRING, 2
|
|
70
|
+
@client_p.write_string "1"
|
|
71
|
+
@client_p.write_field_end
|
|
72
|
+
@client_p.write_field_stop
|
|
73
|
+
@client_p.write_struct_end
|
|
74
|
+
@client_p.write_message_end
|
|
75
|
+
@client_p.trans.flush
|
|
76
|
+
|
|
77
|
+
@client_p.read_message_begin
|
|
78
|
+
@client_p.read_struct_begin
|
|
79
|
+
_, _, fid = @client_p.read_field_begin
|
|
80
|
+
assert_equal 0, fid
|
|
81
|
+
assert_equal 2, @client_p.read_i32
|
|
82
|
+
@client_p.read_field_end
|
|
83
|
+
_, type, _ = @client_p.read_field_begin
|
|
84
|
+
assert_equal type, Thrift::Types::STOP
|
|
85
|
+
@client_p.read_struct_end
|
|
86
|
+
@client_p.read_message_end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def test_coerce_number_list_to_string_list
|
|
91
|
+
send_to_server do
|
|
92
|
+
name = "set_list"
|
|
93
|
+
@client_p.write_message_begin name, Thrift::MessageTypes::CALL, 0
|
|
94
|
+
@client_p.write_struct_begin "#{name}_args"
|
|
95
|
+
@client_p.write_field_begin "l", Thrift::Types::LIST, 1
|
|
96
|
+
@client_p.write_list_begin ::Thrift::Types::I32, 3
|
|
97
|
+
@client_p.write_i32 1
|
|
98
|
+
@client_p.write_i32 2
|
|
99
|
+
@client_p.write_i32 3
|
|
100
|
+
@client_p.write_list_end
|
|
101
|
+
@client_p.write_field_end
|
|
102
|
+
@client_p.write_field_stop
|
|
103
|
+
@client_p.write_struct_end
|
|
104
|
+
@client_p.write_message_end
|
|
105
|
+
@client_p.trans.flush
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
assert_equal ["1", "2", "3"], @handler.last_list
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def test_coerce_strings_on_write_parameter
|
|
112
|
+
@handler.store @n::UserProfile.new(:uid => 123, :name => "Gob")
|
|
113
|
+
|
|
114
|
+
profile = send_to_server do
|
|
115
|
+
@client.retrieve "123"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
assert profile
|
|
119
|
+
assert_equal "Gob", profile.name
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def test_coerce_strings_on_write_struct_field
|
|
123
|
+
send_to_server do
|
|
124
|
+
@client.set_user_friends @n::UserFriends.new(:user => "123")
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
assert @handler.user_friends
|
|
128
|
+
assert_equal 123, @handler.user_friends.user
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def test_coercion_fails_on_write_with_incompatible_types
|
|
132
|
+
assert_raises TypeError do
|
|
133
|
+
@client.store "user_profile"
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
class BadTypesHandler
|
|
138
|
+
def initialize(n)
|
|
139
|
+
@n = n
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def retrieve(uid)
|
|
143
|
+
@n::UserProfile.new(:uid => "123", :name => 123)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def volume_up
|
|
147
|
+
"11"
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def test_coerce_strings_on_processor_write_struct_field
|
|
152
|
+
set_handler BadTypesHandler.new(@n)
|
|
153
|
+
|
|
154
|
+
profile = send_to_server do
|
|
155
|
+
@client.retrieve 123
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
assert profile
|
|
159
|
+
assert_equal "123", profile.name
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def test_coerce_strings_on_processor_write_return_value
|
|
163
|
+
set_handler BadTypesHandler.new(@n)
|
|
164
|
+
|
|
165
|
+
vol = send_to_server do
|
|
166
|
+
@client.volume_up
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
assert vol
|
|
170
|
+
assert_equal 11, vol
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def test_coercion_fails_on_processor_write_with_incompatible_types
|
|
174
|
+
set_handler Object.new.tap {|h|
|
|
175
|
+
def h.retrieve(uid)
|
|
176
|
+
"user_profile"
|
|
177
|
+
end
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
assert_raises Thrift::ApplicationException do
|
|
181
|
+
send_to_server do
|
|
182
|
+
@client.retrieve 123
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
end
|
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
module TestHelper
|
|
2
|
+
def setup_shared
|
|
3
|
+
@client_t, @server_t = Stark.pipe_transport
|
|
4
|
+
@client_p = Thrift::BinaryProtocol.new @client_t
|
|
5
|
+
@server_p = Thrift::BinaryProtocol.new @server_t
|
|
6
|
+
|
|
7
|
+
@n = Module.new
|
|
8
|
+
Stark.materialize self.class::IDL, @n
|
|
9
|
+
@s = @n.module_eval self.class::SERVICE
|
|
10
|
+
@prev_logger = Stark.logger
|
|
11
|
+
@log_stream = StringIO.new
|
|
12
|
+
Stark.logger = Logger.new @log_stream
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def setup_client
|
|
16
|
+
setup_shared
|
|
17
|
+
@client = @n::UserStorage::Client.new @client_p, @client_p
|
|
18
|
+
@handler = Handler.new(Object)
|
|
19
|
+
@server = UserStorage::Processor.new @handler
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def setup_server(handler = nil)
|
|
23
|
+
setup_shared
|
|
24
|
+
@client = @s::Client.new @client_p, @client_p
|
|
25
|
+
set_handler handler
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def set_handler(handler = nil)
|
|
29
|
+
@handler = handler || Handler.new(@n)
|
|
30
|
+
@server = @s::Processor.new @handler
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def teardown
|
|
34
|
+
print @log_stream.string unless passed?
|
|
35
|
+
Stark.logger = @prev_logger
|
|
36
|
+
@client_t.close
|
|
37
|
+
@server_t.close
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class Handler
|
|
41
|
+
def initialize(n)
|
|
42
|
+
@users = {}
|
|
43
|
+
@last_map = nil
|
|
44
|
+
@last_list = nil
|
|
45
|
+
@last_status = nil
|
|
46
|
+
@n = n
|
|
47
|
+
@user_status = nil
|
|
48
|
+
@user_relationship = nil
|
|
49
|
+
@user_friends = nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
attr_accessor :last_map, :last_list, :last_status, :user_status
|
|
53
|
+
|
|
54
|
+
def store(obj)
|
|
55
|
+
@users[obj.uid] = obj
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def retrieve(id)
|
|
59
|
+
@users[id]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def set_map(m)
|
|
63
|
+
@last_map = m
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def set_list(l)
|
|
67
|
+
@last_list = l
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def set_status(s)
|
|
71
|
+
@last_status = s
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def volume_up
|
|
75
|
+
raise @n::RockTooHard.new(:volume => 11)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def make_bitcoins
|
|
79
|
+
sleep 2
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def add(a,b)
|
|
83
|
+
a + b
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def set_user_status(s)
|
|
87
|
+
@user_status = s
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
attr_accessor :user_relationship
|
|
91
|
+
def set_user_relationship(rel)
|
|
92
|
+
@user_relationship = rel
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
attr_accessor :user_friends
|
|
96
|
+
def set_user_friends(fr)
|
|
97
|
+
@user_friends = fr
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def send_to_server
|
|
102
|
+
st = Thread.new do
|
|
103
|
+
@server.process @server_p, @server_p
|
|
104
|
+
end
|
|
105
|
+
yield
|
|
106
|
+
rescue => e
|
|
107
|
+
st = nil
|
|
108
|
+
raise e
|
|
109
|
+
ensure
|
|
110
|
+
st.value if st
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
|
|
3
|
+
require 'stark'
|
|
4
|
+
require 'thrift'
|
|
5
|
+
|
|
6
|
+
require 'test/test_helper'
|
|
7
|
+
|
|
8
|
+
class TestMarshal < Test::Unit::TestCase
|
|
9
|
+
IDL = "test/types.thrift"
|
|
10
|
+
SERVICE = "Types"
|
|
11
|
+
include TestHelper
|
|
12
|
+
|
|
13
|
+
class Handler
|
|
14
|
+
def initialize(n, at = nil, err = nil)
|
|
15
|
+
@n = n
|
|
16
|
+
@at = at || @n::AllTypes.new
|
|
17
|
+
@err = err
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def get_all_types
|
|
21
|
+
@at
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def set_all_types(at)
|
|
25
|
+
@at = at
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def raise_error
|
|
29
|
+
raise @err if @err
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def set_error(err)
|
|
33
|
+
@err = err
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def create_all_types(fields)
|
|
38
|
+
@n::AllTypes.new(fields).tap do |af|
|
|
39
|
+
enum = fields.keys.first.to_s.sub(/^an?_/, '')
|
|
40
|
+
af.field = enum.to_sym
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def setup
|
|
45
|
+
setup_server
|
|
46
|
+
set_handler Handler.new(@n)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_returning_struct
|
|
50
|
+
send_to_server do
|
|
51
|
+
assert @client.get_all_types.field.nil?
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def test_returning_a_list_of_structs
|
|
56
|
+
l = [@n::Element.new(:id => 1, :name => "one"), @n::Element.new(:id => 2, :name => "two")]
|
|
57
|
+
@handler.set_all_types create_all_types(:a_list_of_structs => l)
|
|
58
|
+
|
|
59
|
+
at = send_to_server do
|
|
60
|
+
@client.get_all_types
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
assert_equal :list_of_structs, at.field
|
|
64
|
+
assert_equal 2, at.a_list_of_structs.size
|
|
65
|
+
el = at.a_list_of_structs[0]
|
|
66
|
+
assert_equal 1, el.id
|
|
67
|
+
assert_equal "one", el.name
|
|
68
|
+
el = at.a_list_of_structs[1]
|
|
69
|
+
assert_equal 2, el.id
|
|
70
|
+
assert_equal "two", el.name
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def test_returning_a_map
|
|
74
|
+
ascii = Hash[*(0...128).map{|n| [n, n.chr]}.flatten]
|
|
75
|
+
@handler.set_all_types create_all_types(:a_map => ascii)
|
|
76
|
+
|
|
77
|
+
at = send_to_server do
|
|
78
|
+
@client.get_all_types
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
assert_equal :map, at.field
|
|
82
|
+
assert_equal ascii, at.a_map
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def test_returning_a_set
|
|
86
|
+
primes = begin
|
|
87
|
+
require 'prime'
|
|
88
|
+
Prime::instance.each(256).to_a
|
|
89
|
+
rescue LoadError
|
|
90
|
+
require 'mathn'
|
|
91
|
+
p = Prime.new
|
|
92
|
+
[].tap {|arr| 256.times { arr << p.next } }
|
|
93
|
+
end
|
|
94
|
+
@handler.set_all_types create_all_types(:a_set => primes + primes)
|
|
95
|
+
|
|
96
|
+
at = send_to_server do
|
|
97
|
+
@client.get_all_types
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
assert_equal :set, at.field
|
|
101
|
+
assert_equal Set.new(primes), at.a_set
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def test_raise_no_error
|
|
105
|
+
send_to_server do
|
|
106
|
+
assert @client.raise_error.nil?
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_raise_first_error
|
|
111
|
+
err = @n::AnException.new :message => "An error occurred", :backtrace => caller
|
|
112
|
+
@handler.set_error err
|
|
113
|
+
exception = send_to_server do
|
|
114
|
+
assert_raises @n::AnException do
|
|
115
|
+
@client.raise_error
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
assert_equal err.message, exception.message
|
|
120
|
+
assert_equal err.backtrace, exception.backtrace
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def test_raise_second_error
|
|
124
|
+
@handler.set_error @n::AnotherException.new
|
|
125
|
+
send_to_server do
|
|
126
|
+
assert_raises @n::AnotherException do
|
|
127
|
+
@client.raise_error
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
data/test/test_parser.rb
CHANGED
|
@@ -56,6 +56,17 @@ struct Foo {
|
|
|
56
56
|
EOM
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
def test_list_with_struct
|
|
60
|
+
parse <<-EOM
|
|
61
|
+
struct Foo {
|
|
62
|
+
1: i32 uid
|
|
63
|
+
}
|
|
64
|
+
struct Bar {
|
|
65
|
+
1: list<Foo> foos
|
|
66
|
+
}
|
|
67
|
+
EOM
|
|
68
|
+
end
|
|
69
|
+
|
|
59
70
|
include Stark::Parser::AST
|
|
60
71
|
|
|
61
72
|
def comment(text)
|
|
@@ -355,5 +366,55 @@ namespace rb Blah
|
|
|
355
366
|
assert_field fs[0], 1, "My_union", "fun_union"
|
|
356
367
|
assert_field fs[1], 2, "i32", "integer32"
|
|
357
368
|
assert_field fs[2], 3, "string", "some_characters"
|
|
369
|
+
|
|
370
|
+
s = ary.shift
|
|
371
|
+
assert_equal "StructWithEnumMap", s.name
|
|
372
|
+
|
|
373
|
+
s = ary.shift
|
|
374
|
+
# comment
|
|
375
|
+
|
|
376
|
+
s = ary.shift
|
|
377
|
+
assert_equal "NestedListInList", s.name
|
|
378
|
+
|
|
379
|
+
s = ary.shift
|
|
380
|
+
assert_equal "NestedListInSet", s.name
|
|
381
|
+
|
|
382
|
+
s = ary.shift
|
|
383
|
+
assert_equal "NestedListInMapKey", s.name
|
|
384
|
+
|
|
385
|
+
s = ary.shift
|
|
386
|
+
assert_equal "NestedListInMapValue", s.name
|
|
387
|
+
|
|
388
|
+
s = ary.shift # comment
|
|
389
|
+
s = ary.shift
|
|
390
|
+
assert_equal "NestedSetInList", s.name
|
|
391
|
+
|
|
392
|
+
s = ary.shift
|
|
393
|
+
assert_equal "NestedSetInSet", s.name
|
|
394
|
+
|
|
395
|
+
s = ary.shift
|
|
396
|
+
assert_equal "NestedSetInMapKey", s.name
|
|
397
|
+
|
|
398
|
+
s = ary.shift
|
|
399
|
+
assert_equal "NestedSetInMapValue", s.name
|
|
400
|
+
|
|
401
|
+
s = ary.shift # comment
|
|
402
|
+
s = ary.shift
|
|
403
|
+
assert_equal "NestedMapInList", s.name
|
|
404
|
+
|
|
405
|
+
s = ary.shift
|
|
406
|
+
assert_equal "NestedMapInSet", s.name
|
|
407
|
+
|
|
408
|
+
s = ary.shift
|
|
409
|
+
assert_equal "NestedMapInMapKey", s.name
|
|
410
|
+
|
|
411
|
+
s = ary.shift
|
|
412
|
+
assert_equal "NestedMapInMapValue", s.name
|
|
413
|
+
|
|
414
|
+
s = ary.shift
|
|
415
|
+
assert_equal "HelloService", s.name
|
|
416
|
+
fs = s.functions
|
|
417
|
+
|
|
418
|
+
assert_func fs[0], list("Hello"), "all", nil
|
|
358
419
|
end
|
|
359
420
|
end
|