liveresource 2.0.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/.gitignore +1 -0
- data/BSDL +24 -0
- data/COPYING +59 -0
- data/GPL +339 -0
- data/README.md +289 -0
- data/Rakefile +47 -0
- data/benchmark/benchmark_helper.rb +19 -0
- data/benchmark/method_benchmark.rb +94 -0
- data/lib/live_resource.rb +66 -0
- data/lib/live_resource/attributes.rb +77 -0
- data/lib/live_resource/declarations.rb +200 -0
- data/lib/live_resource/finders.rb +43 -0
- data/lib/live_resource/log_helper.rb +24 -0
- data/lib/live_resource/methods.rb +41 -0
- data/lib/live_resource/methods/dispatcher.rb +176 -0
- data/lib/live_resource/methods/forward.rb +23 -0
- data/lib/live_resource/methods/future.rb +27 -0
- data/lib/live_resource/methods/method.rb +93 -0
- data/lib/live_resource/methods/token.rb +22 -0
- data/lib/live_resource/redis_client.rb +100 -0
- data/lib/live_resource/redis_client/attributes.rb +40 -0
- data/lib/live_resource/redis_client/methods.rb +194 -0
- data/lib/live_resource/redis_client/registration.rb +25 -0
- data/lib/live_resource/resource.rb +44 -0
- data/lib/live_resource/resource_proxy.rb +180 -0
- data/old/benchmark/attribute_benchmark.rb +58 -0
- data/old/benchmark/thread_benchmark.rb +89 -0
- data/old/examples/attribute.rb +22 -0
- data/old/examples/attribute_rmw.rb +30 -0
- data/old/examples/attribute_subscriber.rb +32 -0
- data/old/examples/method_provider_sleep.rb +22 -0
- data/old/examples/methods.rb +37 -0
- data/old/lib/live_resource/subscriber.rb +98 -0
- data/old/redis_test.rb +127 -0
- data/old/state_publisher_test.rb +139 -0
- data/old/test/attribute_modify_test.rb +52 -0
- data/old/test/attribute_options_test.rb +54 -0
- data/old/test/attribute_subscriber_test.rb +94 -0
- data/old/test/composite_resource_test.rb +61 -0
- data/old/test/method_sender_test.rb +41 -0
- data/old/test/redis_api_test.rb +185 -0
- data/old/test/simple_attribute_test.rb +75 -0
- data/test/attribute_test.rb +212 -0
- data/test/declarations_test.rb +119 -0
- data/test/logger_test.rb +44 -0
- data/test/method_call_test.rb +223 -0
- data/test/method_forward_continue_test.rb +83 -0
- data/test/method_params_test.rb +81 -0
- data/test/method_routing_test.rb +59 -0
- data/test/multiple_class_test.rb +47 -0
- data/test/new_api_DISABLED.rb +127 -0
- data/test/test_helper.rb +9 -0
- data/test/volume_create_DISABLED.rb +74 -0
- metadata +129 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class TestClass < Test::Unit::TestCase
|
4
|
+
class Class1
|
5
|
+
include LiveResource::Resource
|
6
|
+
|
7
|
+
@@class_attr = 42
|
8
|
+
|
9
|
+
remote_reader :name
|
10
|
+
remote_writer :write_only
|
11
|
+
remote_accessor :accessor
|
12
|
+
|
13
|
+
resource_name :name
|
14
|
+
resource_class :class_1
|
15
|
+
|
16
|
+
def initialize(name)
|
17
|
+
remote_attribute_write(:name, name)
|
18
|
+
|
19
|
+
self.write_only = 'not yet written'
|
20
|
+
self.accessor = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.class_method1(param1, param2)
|
24
|
+
(param1 + param2).upcase
|
25
|
+
end
|
26
|
+
|
27
|
+
def method1(param1, param2)
|
28
|
+
name + param1 + param2
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.class_attr
|
32
|
+
@@class_attr
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.class_attr=(new_value)
|
36
|
+
@@class_attr = new_value
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.private_class_method1
|
40
|
+
end
|
41
|
+
private_class_method :private_class_method1
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def private_method1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def setup
|
50
|
+
Redis.new.flushall
|
51
|
+
|
52
|
+
LiveResource::RedisClient.logger.level = Logger::INFO
|
53
|
+
|
54
|
+
# Class resources
|
55
|
+
LiveResource::register Class1
|
56
|
+
end
|
57
|
+
|
58
|
+
def teardown
|
59
|
+
LiveResource::stop
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_correct_class_methods
|
63
|
+
assert_equal [:new, :ruby_new, :class_method1, :class_attr, :class_attr=].sort,
|
64
|
+
Class1.remote_methods.sort
|
65
|
+
end
|
66
|
+
|
67
|
+
# TODO: support class attributes (?)
|
68
|
+
# def test_correct_class_attributes
|
69
|
+
# assert_equal [:class_attr], Class1.remote_attributes
|
70
|
+
# end
|
71
|
+
|
72
|
+
def test_correct_instance_methods
|
73
|
+
assert_equal [:method1], Class1.ruby_new("foo").remote_methods
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_correct_instance_attributes
|
77
|
+
assert_equal [:name, :write_only=, :accessor, :accessor=].sort,
|
78
|
+
Class1.ruby_new("foo").remote_attributes.sort
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_call_class_method
|
82
|
+
class_resource = LiveResource::find(:class_1)
|
83
|
+
|
84
|
+
assert class_resource.respond_to? :new
|
85
|
+
assert class_resource.respond_to? :class_method1
|
86
|
+
|
87
|
+
assert_equal "FOOBAR", class_resource.class_method1("foo", "bar")
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_create_instances
|
91
|
+
class_resource = LiveResource::find(:class_1)
|
92
|
+
|
93
|
+
assert_equal 0, LiveResource::all(:class_1).length
|
94
|
+
|
95
|
+
class_resource.new("bob")
|
96
|
+
class_resource.new("fred")
|
97
|
+
class_resource.new("sue")
|
98
|
+
|
99
|
+
assert_equal 3, LiveResource::all(:class_1).length
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_new_returns_resource_proxy
|
103
|
+
class_resource = LiveResource::find(:class_1)
|
104
|
+
bob = class_resource.new("bob")
|
105
|
+
|
106
|
+
assert_equal "bob jones", bob.method1(" ", "jones")
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_resource_proxy_can_get_attributes
|
110
|
+
class_resource = LiveResource::find(:class_1)
|
111
|
+
bob = class_resource.new("bob")
|
112
|
+
|
113
|
+
assert_equal "bob", bob.name
|
114
|
+
assert_equal nil, bob.accessor
|
115
|
+
|
116
|
+
bob.accessor = "new value"
|
117
|
+
assert_equal "new value", bob.accessor
|
118
|
+
end
|
119
|
+
end
|
data/test/logger_test.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
2
|
+
|
3
|
+
class C
|
4
|
+
include LiveResource::LogHelper
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@log_backend = StringIO.new("", "r+")
|
8
|
+
self.logger = Logger.new(@log_backend)
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate_debug
|
12
|
+
debug "my debug message"
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate_fatal
|
16
|
+
fatal "my fatal message"
|
17
|
+
end
|
18
|
+
|
19
|
+
def dump
|
20
|
+
@log_backend.rewind
|
21
|
+
@log_backend.readlines
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class LoggerTest < Test::Unit::TestCase
|
26
|
+
def test_basic_logging
|
27
|
+
c = C.new
|
28
|
+
c.generate_fatal
|
29
|
+
|
30
|
+
assert_match "my fatal message", c.dump[0]
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_changing_log_levels
|
34
|
+
c = C.new
|
35
|
+
c.logger.level = Logger::WARN
|
36
|
+
|
37
|
+
c.generate_debug
|
38
|
+
assert_equal 0, c.dump.length
|
39
|
+
|
40
|
+
c.logger.level = Logger::DEBUG
|
41
|
+
c.generate_debug
|
42
|
+
assert_match "my debug message", c.dump[0]
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class MethodTest < Test::Unit::TestCase
|
4
|
+
class MyClass
|
5
|
+
attr_accessor :a, :b
|
6
|
+
|
7
|
+
def initialize(a, b)
|
8
|
+
@a = a
|
9
|
+
@b = b
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# We slice, we dice, we can cut through tin cans!
|
14
|
+
class Server
|
15
|
+
include LiveResource::Resource
|
16
|
+
|
17
|
+
resource_class :server
|
18
|
+
resource_name :object_id
|
19
|
+
|
20
|
+
def meaning
|
21
|
+
42
|
22
|
+
end
|
23
|
+
|
24
|
+
def upcase(str)
|
25
|
+
str.upcase
|
26
|
+
end
|
27
|
+
|
28
|
+
def slow_upcase(str)
|
29
|
+
10.times { Thread.pass }
|
30
|
+
str.upcase
|
31
|
+
end
|
32
|
+
|
33
|
+
def two_second_upcase(str)
|
34
|
+
sleep 2
|
35
|
+
str.upcase
|
36
|
+
end
|
37
|
+
|
38
|
+
def add(a, b)
|
39
|
+
a + b
|
40
|
+
end
|
41
|
+
|
42
|
+
def reverse(arr)
|
43
|
+
arr.reverse
|
44
|
+
end
|
45
|
+
|
46
|
+
def swap_a_b(myclass)
|
47
|
+
a, b = myclass.a, myclass.b
|
48
|
+
myclass.b = a
|
49
|
+
myclass.a = b
|
50
|
+
myclass
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def setup
|
55
|
+
Redis.new.flushall
|
56
|
+
|
57
|
+
Server.new
|
58
|
+
end
|
59
|
+
|
60
|
+
def teardown
|
61
|
+
LiveResource::stop
|
62
|
+
end
|
63
|
+
|
64
|
+
# TODO: some test like this
|
65
|
+
#
|
66
|
+
# def test_method_done
|
67
|
+
# rs = LiveResource::RedisSpace.new('test')
|
68
|
+
#
|
69
|
+
# assert_raise(ArgumentError) do
|
70
|
+
# rs.method_done? '1' # Doesn't exist yet
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# rs.method_push '1'
|
74
|
+
# assert_equal false, rs.method_done?('1')
|
75
|
+
#
|
76
|
+
# rs.method_wait
|
77
|
+
# assert_equal false, rs.method_done?('1')
|
78
|
+
#
|
79
|
+
# rs.result_set '1', 42
|
80
|
+
# rs.method_done '1'
|
81
|
+
# assert_equal true, rs.method_done?('1')
|
82
|
+
# end
|
83
|
+
|
84
|
+
def test_synchronous_method
|
85
|
+
starting_keys = Redis.new.dbsize
|
86
|
+
client = LiveResource::any(:server)
|
87
|
+
|
88
|
+
# Zero parameters
|
89
|
+
assert_equal 42, client.meaning
|
90
|
+
|
91
|
+
# One parameter (simple)
|
92
|
+
assert_equal "FOOBAR", client.upcase("foobar")
|
93
|
+
|
94
|
+
# One parameter (complex)
|
95
|
+
assert_equal [3, 2, 1], client.reverse([1, 2, 3])
|
96
|
+
|
97
|
+
# Two parameters
|
98
|
+
assert_equal 3, client.add(1, 2)
|
99
|
+
|
100
|
+
# Non-native class
|
101
|
+
myclass = client.swap_a_b MyClass.new("a", "b")
|
102
|
+
assert_equal "b", myclass.a
|
103
|
+
assert_equal "a", myclass.b
|
104
|
+
|
105
|
+
# Should have no junk left over in Redis
|
106
|
+
assert_equal starting_keys, Redis.new.dbsize
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_method_with_no_response
|
110
|
+
starting_keys = Redis.new.dbsize
|
111
|
+
client = LiveResource::any(:server)
|
112
|
+
|
113
|
+
# Do one async call; dispatcher should auto-clean up
|
114
|
+
client.upcase! "foobar"
|
115
|
+
|
116
|
+
# Do a sync call afterward to make sure the first is done
|
117
|
+
client.upcase "foobar"
|
118
|
+
|
119
|
+
assert_equal starting_keys, Redis.new.dbsize
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_no_matching_method
|
123
|
+
client = LiveResource::any(:server)
|
124
|
+
|
125
|
+
assert_raise(NoMethodError) do
|
126
|
+
client.this_is_not_a_valid_method
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_method_stress
|
131
|
+
starting_keys = Redis.new.dbsize
|
132
|
+
client = LiveResource::any(:server)
|
133
|
+
|
134
|
+
100.times do
|
135
|
+
client.upcase("foobar")
|
136
|
+
end
|
137
|
+
|
138
|
+
# Should have no junk left over in Redis
|
139
|
+
assert_equal starting_keys, Redis.new.dbsize
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_method_call_with_future
|
143
|
+
starting_keys = Redis.new.dbsize
|
144
|
+
client = LiveResource::any(:server)
|
145
|
+
|
146
|
+
value = client.slow_upcase? 'foobar'
|
147
|
+
|
148
|
+
assert_not_nil value
|
149
|
+
assert_equal false, value.done?
|
150
|
+
|
151
|
+
# Wait for valid result.
|
152
|
+
assert_equal 'FOOBAR', value.value
|
153
|
+
|
154
|
+
# Should have no junk left over in Redis, BUT we can still get the
|
155
|
+
# future's value as many times as we want.
|
156
|
+
assert_equal starting_keys, Redis.new.dbsize
|
157
|
+
assert_equal 'FOOBAR', value.value
|
158
|
+
end
|
159
|
+
|
160
|
+
# Similar test to above, but in this case we don't wait for done until
|
161
|
+
# after we already know the action is done.
|
162
|
+
def test_wait_for_done_after_done
|
163
|
+
client = LiveResource::any(:server)
|
164
|
+
|
165
|
+
# Repeat a bunch of times -- this helps catch a race
|
166
|
+
# condition in done_with?
|
167
|
+
100.times do
|
168
|
+
value = client.slow_upcase? 'foobar'
|
169
|
+
|
170
|
+
while !value.done?
|
171
|
+
Thread.pass
|
172
|
+
end
|
173
|
+
|
174
|
+
# Result should be ready for us
|
175
|
+
assert_equal 'FOOBAR', value.value
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_method_timeout_success
|
180
|
+
client = LiveResource::any(:server)
|
181
|
+
value = client.upcase? "foobar"
|
182
|
+
|
183
|
+
assert_equal "FOOBAR", value.value(1)
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_method_timeout_failure
|
187
|
+
client = LiveResource::any(:server)
|
188
|
+
|
189
|
+
LiveResource::stop # No servers
|
190
|
+
|
191
|
+
starting_keys = Redis.new.dbsize
|
192
|
+
|
193
|
+
assert_raise(RuntimeError) do
|
194
|
+
value = client.upcase? "foobar"
|
195
|
+
value.value(1)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Should have no junk left over in Redis
|
199
|
+
assert_equal starting_keys, Redis.new.dbsize
|
200
|
+
end
|
201
|
+
|
202
|
+
def test_method_completes_after_timeout
|
203
|
+
starting_keys = Redis.new.dbsize
|
204
|
+
client = LiveResource::any(:server)
|
205
|
+
|
206
|
+
# Turn up log level; this test will generate an appropriate warning.
|
207
|
+
old_level = LiveResource::RedisClient.logger.level = Logger::ERROR
|
208
|
+
|
209
|
+
# This will fail (as above) but the server will actually complete it a second
|
210
|
+
# later. Need to make sure server cleans up ok.
|
211
|
+
assert_raise(RuntimeError) do
|
212
|
+
value = client.two_second_upcase? "foobar"
|
213
|
+
value.value(1)
|
214
|
+
end
|
215
|
+
|
216
|
+
sleep 2
|
217
|
+
|
218
|
+
# Should have no junk left over in Redis
|
219
|
+
assert_equal starting_keys, Redis.new.dbsize
|
220
|
+
|
221
|
+
LiveResource::RedisClient.logger.level = old_level
|
222
|
+
end
|
223
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class ForwardContinueTest < Test::Unit::TestCase
|
4
|
+
class Class1
|
5
|
+
include LiveResource::Resource
|
6
|
+
|
7
|
+
resource_name :object_id
|
8
|
+
resource_class :class_1
|
9
|
+
|
10
|
+
def method1(param1, param2)
|
11
|
+
c2 = LiveResource::any(:class_2)
|
12
|
+
c3 = LiveResource::any(:class_3)
|
13
|
+
param3 = "baz"
|
14
|
+
|
15
|
+
forward(c2, :method2, param1, param2, param3).continue(c3, :method3)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Class2
|
20
|
+
include LiveResource::Resource
|
21
|
+
|
22
|
+
resource_name :object_id
|
23
|
+
resource_class :class_2
|
24
|
+
|
25
|
+
def method2(param1, param2, param3)
|
26
|
+
[param1, param2, param3].join('-')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Class3
|
31
|
+
include LiveResource::Resource
|
32
|
+
|
33
|
+
resource_name :object_id
|
34
|
+
resource_class :class_3
|
35
|
+
|
36
|
+
def method3(param1)
|
37
|
+
param1.upcase
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup
|
42
|
+
Redis.new.flushall
|
43
|
+
|
44
|
+
Class1.new
|
45
|
+
Class2.new
|
46
|
+
Class3.new
|
47
|
+
end
|
48
|
+
|
49
|
+
def teardown
|
50
|
+
LiveResource::stop
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_instances_have_methods
|
54
|
+
i = LiveResource::all(:class_1).first
|
55
|
+
|
56
|
+
assert i.respond_to?(:method1), "instance does not respond to method1"
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_instances_have_async_methods
|
60
|
+
i = LiveResource::all(:class_1).first
|
61
|
+
|
62
|
+
assert i.respond_to?(:method1!), "instance does not respond to method1!"
|
63
|
+
assert i.respond_to?(:method1?), "instance does not respond to method1?"
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_instance_does_not_respond_to_invalid_methods
|
67
|
+
i = LiveResource::all(:class_1).first
|
68
|
+
|
69
|
+
assert !i.respond_to?(:method2), "instance should not respond to method2"
|
70
|
+
assert !i.respond_to?(:method2!), "instance should not respond to method2!"
|
71
|
+
assert !i.respond_to?(:method2?), "instance should not respond to method2?"
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_message_path
|
75
|
+
starting_keys = Redis.new.dbsize
|
76
|
+
|
77
|
+
# LiveResource::RedisClient::logger.level = Logger::DEBUG
|
78
|
+
assert_equal "FOO-BAR-BAZ", LiveResource::any(:class_1).method1("foo", "bar")
|
79
|
+
|
80
|
+
# Should have no junk left over in Redis
|
81
|
+
assert_equal starting_keys, Redis.new.dbsize
|
82
|
+
end
|
83
|
+
end
|