stark 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|