liveresource 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.gitignore +1 -0
  2. data/BSDL +24 -0
  3. data/COPYING +59 -0
  4. data/GPL +339 -0
  5. data/README.md +289 -0
  6. data/Rakefile +47 -0
  7. data/benchmark/benchmark_helper.rb +19 -0
  8. data/benchmark/method_benchmark.rb +94 -0
  9. data/lib/live_resource.rb +66 -0
  10. data/lib/live_resource/attributes.rb +77 -0
  11. data/lib/live_resource/declarations.rb +200 -0
  12. data/lib/live_resource/finders.rb +43 -0
  13. data/lib/live_resource/log_helper.rb +24 -0
  14. data/lib/live_resource/methods.rb +41 -0
  15. data/lib/live_resource/methods/dispatcher.rb +176 -0
  16. data/lib/live_resource/methods/forward.rb +23 -0
  17. data/lib/live_resource/methods/future.rb +27 -0
  18. data/lib/live_resource/methods/method.rb +93 -0
  19. data/lib/live_resource/methods/token.rb +22 -0
  20. data/lib/live_resource/redis_client.rb +100 -0
  21. data/lib/live_resource/redis_client/attributes.rb +40 -0
  22. data/lib/live_resource/redis_client/methods.rb +194 -0
  23. data/lib/live_resource/redis_client/registration.rb +25 -0
  24. data/lib/live_resource/resource.rb +44 -0
  25. data/lib/live_resource/resource_proxy.rb +180 -0
  26. data/old/benchmark/attribute_benchmark.rb +58 -0
  27. data/old/benchmark/thread_benchmark.rb +89 -0
  28. data/old/examples/attribute.rb +22 -0
  29. data/old/examples/attribute_rmw.rb +30 -0
  30. data/old/examples/attribute_subscriber.rb +32 -0
  31. data/old/examples/method_provider_sleep.rb +22 -0
  32. data/old/examples/methods.rb +37 -0
  33. data/old/lib/live_resource/subscriber.rb +98 -0
  34. data/old/redis_test.rb +127 -0
  35. data/old/state_publisher_test.rb +139 -0
  36. data/old/test/attribute_modify_test.rb +52 -0
  37. data/old/test/attribute_options_test.rb +54 -0
  38. data/old/test/attribute_subscriber_test.rb +94 -0
  39. data/old/test/composite_resource_test.rb +61 -0
  40. data/old/test/method_sender_test.rb +41 -0
  41. data/old/test/redis_api_test.rb +185 -0
  42. data/old/test/simple_attribute_test.rb +75 -0
  43. data/test/attribute_test.rb +212 -0
  44. data/test/declarations_test.rb +119 -0
  45. data/test/logger_test.rb +44 -0
  46. data/test/method_call_test.rb +223 -0
  47. data/test/method_forward_continue_test.rb +83 -0
  48. data/test/method_params_test.rb +81 -0
  49. data/test/method_routing_test.rb +59 -0
  50. data/test/multiple_class_test.rb +47 -0
  51. data/test/new_api_DISABLED.rb +127 -0
  52. data/test/test_helper.rb +9 -0
  53. data/test/volume_create_DISABLED.rb +74 -0
  54. 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
@@ -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