siberite-client 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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/LICENSE +14 -0
- data/README.md +63 -0
- data/Rakefile +18 -0
- data/lib/siberite-client.rb +1 -0
- data/lib/siberite.rb +9 -0
- data/lib/siberite/client.rb +202 -0
- data/lib/siberite/client/blocking.rb +36 -0
- data/lib/siberite/client/envelope.rb +25 -0
- data/lib/siberite/client/json.rb +16 -0
- data/lib/siberite/client/namespace.rb +29 -0
- data/lib/siberite/client/partitioning.rb +35 -0
- data/lib/siberite/client/proxy.rb +15 -0
- data/lib/siberite/client/stats_helper.rb +122 -0
- data/lib/siberite/client/transactional.rb +125 -0
- data/lib/siberite/client/unmarshal.rb +32 -0
- data/lib/siberite/client/version.rb +3 -0
- data/lib/siberite/config.rb +48 -0
- data/siberite-client.gemspec +35 -0
- data/spec/siberite/client/blocking_spec.rb +29 -0
- data/spec/siberite/client/envelope_spec.rb +45 -0
- data/spec/siberite/client/json_spec.rb +40 -0
- data/spec/siberite/client/namespace_spec.rb +54 -0
- data/spec/siberite/client/partitioning_spec.rb +33 -0
- data/spec/siberite/client/transactional_spec.rb +273 -0
- data/spec/siberite/client/unmarshal_spec.rb +68 -0
- data/spec/siberite/client_spec.rb +175 -0
- data/spec/siberite/config/siberite.yml +42 -0
- data/spec/siberite/config_spec.rb +72 -0
- data/spec/siberite_benchmark.rb +26 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +33 -0
- metadata +205 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Siberite::Client::Json do
|
4
|
+
describe "Instance Methods" do
|
5
|
+
before do
|
6
|
+
@raw_client = Siberite::Client.new(*Siberite::Config.default)
|
7
|
+
@client = Siberite::Client::Json.new(@raw_client)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#get" do
|
11
|
+
it "parses json" do
|
12
|
+
mock(@raw_client).get('a_queue') { '{"a": 1, "b": [{"c": 2}]}' }
|
13
|
+
@client.get('a_queue').should == {"a" => 1, "b" => ["c" => 2]}
|
14
|
+
end
|
15
|
+
|
16
|
+
# wtf is up with this test?
|
17
|
+
it "uses a HashWithIndifferentAccess" do
|
18
|
+
mock(@raw_client).get('a_queue') { '{"a": 1, "b": [{"c": 2}]}' }
|
19
|
+
@client.get('a_queue').class.should == HashWithIndifferentAccess
|
20
|
+
end
|
21
|
+
|
22
|
+
it "passes through non-strings" do
|
23
|
+
mock(@raw_client).get('a_queue') { {:key => "value"} }
|
24
|
+
@client.get('a_queue').should == {:key => "value"}
|
25
|
+
end
|
26
|
+
|
27
|
+
it "passes through strings that are not json" do
|
28
|
+
mock(@raw_client).get('a_queue') { "I am not JSON" }
|
29
|
+
@client.get('a_queue').should == "I am not JSON"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class HashWithIndifferentAccess < Hash
|
36
|
+
def initialize(hash = {})
|
37
|
+
super()
|
38
|
+
merge!(hash)
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Siberite::Client::Namespace do
|
4
|
+
describe "Instance Methods" do
|
5
|
+
before do
|
6
|
+
@raw_client = Siberite::Client.new(*Siberite::Config.default)
|
7
|
+
@client = Siberite::Client::Namespace.new('some_namespace', @raw_client)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#set" do
|
11
|
+
it "prepends a namespace to the key" do
|
12
|
+
mock(@raw_client).set('some_namespace:a_queue', :mcguffin)
|
13
|
+
@client.set('a_queue', :mcguffin)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#get" do
|
18
|
+
it "prepends a namespace to the key" do
|
19
|
+
mock(@raw_client).get('some_namespace:a_queue')
|
20
|
+
@client.get('a_queue')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#delete" do
|
25
|
+
it "prepends a namespace to the key" do
|
26
|
+
mock(@raw_client).delete('some_namespace:a_queue')
|
27
|
+
@client.delete('a_queue')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#flush" do
|
32
|
+
it "prepends a namespace to the key" do
|
33
|
+
mock(@raw_client).flush('some_namespace:a_queue')
|
34
|
+
@client.flush('a_queue')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#stat" do
|
39
|
+
it "prepends a namespace to the key" do
|
40
|
+
mock(@raw_client).stat('some_namespace:a_queue')
|
41
|
+
@client.stat('a_queue')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#available_queues" do
|
46
|
+
it "only returns namespaced queues" do
|
47
|
+
@raw_client.set('some_namespace:namespaced_queue', 'foo')
|
48
|
+
@raw_client.set('unnamespaced_queue', 'foo')
|
49
|
+
|
50
|
+
@client.available_queues.should == ['namespaced_queue']
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Siberite::Client::Partitioning do
|
4
|
+
before do
|
5
|
+
@client_1 = Siberite::Client.new(*Siberite::Config.default)
|
6
|
+
@client_2 = Siberite::Client.new(*Siberite::Config.default)
|
7
|
+
@default_client = Siberite::Client.new(*Siberite::Config.default)
|
8
|
+
|
9
|
+
@client = Siberite::Client::Partitioning.new(
|
10
|
+
'queue1' => @client_1,
|
11
|
+
['queue2', 'queue3'] => @client_2,
|
12
|
+
default: @default_client
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
%w(set get delete flush stat).each do |method|
|
17
|
+
describe "##{method}" do
|
18
|
+
it "routes to the correct client" do
|
19
|
+
mock(@client_1).__send__(method, 'queue1')
|
20
|
+
@client.send(method, 'queue1')
|
21
|
+
|
22
|
+
mock(@client_2).__send__(method, 'queue2')
|
23
|
+
@client.send(method, 'queue2')
|
24
|
+
|
25
|
+
mock(@client_2).__send__(method, 'queue3/queue_arg')
|
26
|
+
@client.send(method, 'queue3/queue_arg')
|
27
|
+
|
28
|
+
mock(@default_client).__send__(method, 'queue4')
|
29
|
+
@client.send(method, 'queue4')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,273 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Siberite::Client::Transactional" do
|
4
|
+
before do
|
5
|
+
@raw_client = Siberite::Client.new(*Siberite::Config.default)
|
6
|
+
@client = Siberite::Client::Transactional.new(@raw_client)
|
7
|
+
@queue = "some_queue"
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "integration" do
|
11
|
+
def get_job
|
12
|
+
job = nil
|
13
|
+
job = @client.get(@queue) until job
|
14
|
+
job
|
15
|
+
end
|
16
|
+
|
17
|
+
it "processes normal jobs" do
|
18
|
+
returns = [:mcguffin]
|
19
|
+
stub(@raw_client).get(@queue, anything) { returns.shift }
|
20
|
+
stub(@raw_client).get_from_last(@queue + "_errors", anything)
|
21
|
+
|
22
|
+
mock(@raw_client).get_from_last(@queue, :close => true)
|
23
|
+
|
24
|
+
get_job.should == :mcguffin
|
25
|
+
@client.current_try.should == 1
|
26
|
+
@client.get(@queue) # simulate next get run
|
27
|
+
end
|
28
|
+
|
29
|
+
it "processes successful retries" do
|
30
|
+
returns = [Siberite::Client::Transactional::RetryableJob.new(1, :mcguffin)]
|
31
|
+
stub(@raw_client).get_from_last(@queue + "_errors", anything) { returns.shift }
|
32
|
+
stub(@raw_client).get(@queue, anything)
|
33
|
+
|
34
|
+
mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
|
35
|
+
|
36
|
+
get_job.should == :mcguffin
|
37
|
+
@client.current_try.should == 2
|
38
|
+
@client.get(@queue) # simulate next get run
|
39
|
+
end
|
40
|
+
|
41
|
+
it "processes normal jobs that should retry" do
|
42
|
+
returns = [:mcguffin]
|
43
|
+
stub(@raw_client).get(@queue, anything) { returns.shift }
|
44
|
+
stub(@raw_client).get_from_last(@queue + "_errors", anything)
|
45
|
+
|
46
|
+
mock(@raw_client).set(@queue + "_errors", anything) do |q,j|
|
47
|
+
j.retries.should == 1
|
48
|
+
j.job.should == :mcguffin
|
49
|
+
end
|
50
|
+
mock(@raw_client).get_from_last(@queue, :close => true)
|
51
|
+
|
52
|
+
get_job.should == :mcguffin
|
53
|
+
@client.current_try.should == 1
|
54
|
+
|
55
|
+
@client.retry
|
56
|
+
@client.get(@queue) # simulate next get run
|
57
|
+
end
|
58
|
+
|
59
|
+
it "processes retries that should retry" do
|
60
|
+
returns = [Siberite::Client::Transactional::RetryableJob.new(1, :mcguffin)]
|
61
|
+
stub(@raw_client).get_from_last(@queue + "_errors", :open => true) { returns.shift }
|
62
|
+
stub(@raw_client).get(@queue, anything)
|
63
|
+
mock(@raw_client).set(@queue + "_errors", anything) do |q,j|
|
64
|
+
j.retries.should == 2
|
65
|
+
j.job.should == :mcguffin
|
66
|
+
end
|
67
|
+
mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
|
68
|
+
|
69
|
+
get_job.should == :mcguffin
|
70
|
+
@client.current_try.should == 2
|
71
|
+
|
72
|
+
@client.retry
|
73
|
+
@client.get(@queue) # simulate next get run
|
74
|
+
end
|
75
|
+
|
76
|
+
it "processes retries that should give up" do
|
77
|
+
returns = [Siberite::Client::Transactional::RetryableJob.new(Siberite::Client::Transactional::DEFAULT_RETRIES - 1, :mcguffin)]
|
78
|
+
stub(@raw_client).get_from_last(@queue + "_errors", :open => true) { returns.shift }
|
79
|
+
stub(@raw_client).get(@queue, anything)
|
80
|
+
mock(@raw_client).set.never
|
81
|
+
mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
|
82
|
+
|
83
|
+
get_job.should == :mcguffin
|
84
|
+
@client.current_try.should == Siberite::Client::Transactional::DEFAULT_RETRIES
|
85
|
+
|
86
|
+
lambda { @client.retry }.should raise_error(Siberite::Client::Transactional::RetriesExceeded)
|
87
|
+
@client.get(@queue) # simulate next get run
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "Instance Methods" do
|
92
|
+
before do
|
93
|
+
stub(@client).rand { 1 }
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "#get" do
|
97
|
+
it "asks for a transaction" do
|
98
|
+
mock(@raw_client).get(@queue, :open => true) { :mcguffin }
|
99
|
+
@client.get(@queue).should == :mcguffin
|
100
|
+
end
|
101
|
+
|
102
|
+
it "is nil when the primary queue is empty and selected" do
|
103
|
+
mock(@client).rand { Siberite::Client::Transactional::ERROR_PROCESSING_RATE + 0.05 }
|
104
|
+
mock(@raw_client).get(@queue, anything) { nil }
|
105
|
+
mock(@raw_client).get(@queue + "_errors", :open => true).never
|
106
|
+
@client.get(@queue).should be_nil
|
107
|
+
end
|
108
|
+
|
109
|
+
it "is nil when the error queue is empty and selected" do
|
110
|
+
mock(@client).rand { Siberite::Client::Transactional::ERROR_PROCESSING_RATE - 0.05 }
|
111
|
+
mock(@raw_client).get(@queue, anything).never
|
112
|
+
mock(@raw_client).get_from_last(@queue + "_errors", :open => true) { nil }
|
113
|
+
@client.get(@queue).should be_nil
|
114
|
+
end
|
115
|
+
|
116
|
+
it "returns the payload of a RetryableJob" do
|
117
|
+
stub(@client).rand { 0 }
|
118
|
+
mock(@raw_client).get_from_last(@queue + "_errors", anything) do
|
119
|
+
Siberite::Client::Transactional::RetryableJob.new(1, :mcmuffin)
|
120
|
+
end
|
121
|
+
|
122
|
+
@client.get(@queue).should == :mcmuffin
|
123
|
+
end
|
124
|
+
|
125
|
+
it "closes an open transaction with no retries" do
|
126
|
+
stub(@raw_client).get(@queue, anything) { :mcguffin }
|
127
|
+
@client.get(@queue)
|
128
|
+
|
129
|
+
mock(@raw_client).get_from_last(@queue, :close => true)
|
130
|
+
@client.get(@queue)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "closes an open transaction with retries" do
|
134
|
+
stub(@client).rand { 0 }
|
135
|
+
stub(@raw_client).get_from_last(@queue + "_errors", :open => true) do
|
136
|
+
Siberite::Client::Transactional::RetryableJob.new(1, :mcmuffin)
|
137
|
+
end
|
138
|
+
@client.get(@queue)
|
139
|
+
|
140
|
+
mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
|
141
|
+
@client.get(@queue)
|
142
|
+
end
|
143
|
+
|
144
|
+
it "prevents transactional gets across multiple queues" do
|
145
|
+
stub(@raw_client).get(@queue, anything) { :mcguffin }
|
146
|
+
@client.get(@queue)
|
147
|
+
|
148
|
+
lambda do
|
149
|
+
@client.get("transaction_fail")
|
150
|
+
end.should raise_error(Siberite::Client::Transactional::MultipleQueueException)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "#retry" do
|
155
|
+
before do
|
156
|
+
stub(@raw_client).get(@queue, anything) { :mcmuffin }
|
157
|
+
stub(@raw_client).get_from_last
|
158
|
+
@client.get(@queue)
|
159
|
+
end
|
160
|
+
|
161
|
+
it "raises an exception if called when there is no open transaction" do
|
162
|
+
@client.close_last_transaction
|
163
|
+
lambda { @client.retry }.should raise_error(Siberite::Client::Transactional::NoOpenTransaction)
|
164
|
+
end
|
165
|
+
|
166
|
+
it "raises an exception if retry has already been called" do
|
167
|
+
@client.retry
|
168
|
+
lambda { @client.retry }.should raise_error(Siberite::Client::Transactional::NoOpenTransaction)
|
169
|
+
end
|
170
|
+
|
171
|
+
it "enqueues a fresh failed job to the errors queue with a retry count" do
|
172
|
+
mock(@raw_client).set(@queue + "_errors", anything) do |queue, job|
|
173
|
+
job.retries.should == 1
|
174
|
+
job.job.should == :mcmuffin
|
175
|
+
end
|
176
|
+
@client.retry.should be_truthy
|
177
|
+
end
|
178
|
+
|
179
|
+
it "allows specification of the job to retry" do
|
180
|
+
mock(@raw_client).set(@queue + "_errors", anything) do |queue, job|
|
181
|
+
job.retries.should == 1
|
182
|
+
job.job.should == :revised_mcmuffin
|
183
|
+
end
|
184
|
+
@client.retry(:revised_mcmuffin).should be_truthy
|
185
|
+
end
|
186
|
+
|
187
|
+
it "increments the retry count and re-enqueues the retried job" do
|
188
|
+
stub(@client).rand { 0 }
|
189
|
+
stub(@raw_client).get_from_last(@queue + "_errors", anything) do
|
190
|
+
Siberite::Client::Transactional::RetryableJob.new(1, :mcmuffin)
|
191
|
+
end
|
192
|
+
|
193
|
+
mock(@raw_client).set(@queue + "_errors", anything) do |queue, job|
|
194
|
+
job.retries.should == 2
|
195
|
+
job.job.should == :mcmuffin
|
196
|
+
end
|
197
|
+
|
198
|
+
@client.get(@queue)
|
199
|
+
@client.retry.should be_truthy
|
200
|
+
end
|
201
|
+
|
202
|
+
it "does not enqueue the retried job after too many tries" do
|
203
|
+
stub(@client).rand { 0 }
|
204
|
+
stub(@raw_client).get_from_last(@queue + "_errors", :open => true) do
|
205
|
+
Siberite::Client::Transactional::RetryableJob.new(Siberite::Client::Transactional::DEFAULT_RETRIES - 1, :mcmuffin)
|
206
|
+
end
|
207
|
+
mock(@raw_client).set(@queue + "_errors", anything).never
|
208
|
+
mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
|
209
|
+
@client.get(@queue)
|
210
|
+
lambda { @client.retry }.should raise_error(Siberite::Client::Transactional::RetriesExceeded)
|
211
|
+
end
|
212
|
+
|
213
|
+
it "closes an open transaction with no retries" do
|
214
|
+
stub(@raw_client).get(@queue, anything) { :mcguffin }
|
215
|
+
@client.get(@queue)
|
216
|
+
|
217
|
+
mock(@raw_client).get_from_last(@queue, :close => true)
|
218
|
+
@client.retry
|
219
|
+
end
|
220
|
+
|
221
|
+
it "closes an open transaction with retries" do
|
222
|
+
stub(@client).rand { 0 }
|
223
|
+
stub(@raw_client).get_from_last(@queue + "_errors", :open => true) do
|
224
|
+
Siberite::Client::Transactional::RetryableJob.new(1, :mcmuffin)
|
225
|
+
end
|
226
|
+
@client.get(@queue)
|
227
|
+
|
228
|
+
mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
|
229
|
+
@client.retry
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
describe "#read_from_error_queue?" do
|
234
|
+
it "returns the error queue ERROR_PROCESSING_RATE pct. of the time" do
|
235
|
+
mock(@client).rand { Siberite::Client::Transactional::ERROR_PROCESSING_RATE - 0.05 }
|
236
|
+
@client.send(:read_from_error_queue?).should == true
|
237
|
+
end
|
238
|
+
|
239
|
+
it "returns the normal queue most of the time" do
|
240
|
+
mock(@client).rand { Siberite::Client::Transactional::ERROR_PROCESSING_RATE + 0.05 }
|
241
|
+
@client.send(:read_from_error_queue?).should == false
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe "#close_last_transaction" do
|
246
|
+
it "does nothing if there is no last transaction" do
|
247
|
+
mock(@raw_client).get_from_last(@queue, :close => true).never
|
248
|
+
mock(@raw_client).get_from_last(@queue + "_errors", :close => true).never
|
249
|
+
@client.send(:close_last_transaction)
|
250
|
+
end
|
251
|
+
|
252
|
+
it "closes the normal queue if the job was pulled off of the normal queue" do
|
253
|
+
mock(@client).read_from_error_queue? { false }
|
254
|
+
mock(@raw_client).get(@queue, :open => true) { :mcguffin }
|
255
|
+
mock(@raw_client).get_from_last(@queue, :close => true)
|
256
|
+
mock(@raw_client).get_from_last(@queue + "_errors", :close => true).never
|
257
|
+
|
258
|
+
@client.get(@queue).should == :mcguffin
|
259
|
+
@client.send(:close_last_transaction)
|
260
|
+
end
|
261
|
+
|
262
|
+
it "closes the error queue if the job was pulled off of the error queue" do
|
263
|
+
mock(@client).read_from_error_queue? { true }
|
264
|
+
mock(@raw_client).get_from_last(@queue + "_errors", :open => true) { Siberite::Client::Transactional::RetryableJob.new 1, :mcguffin }
|
265
|
+
mock(@raw_client).get_from_last(@queue, :close => true).never
|
266
|
+
mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
|
267
|
+
|
268
|
+
@client.get(@queue).should == :mcguffin
|
269
|
+
@client.send(:close_last_transaction)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Siberite::Client::Unmarshal do
|
4
|
+
describe "Instance Methods" do
|
5
|
+
before do
|
6
|
+
@raw_client = Siberite::Client.new(*Siberite::Config.default)
|
7
|
+
@client = Siberite::Client::Unmarshal.new(@raw_client)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#get" do
|
11
|
+
it "integrates" do
|
12
|
+
@client.set('a_queue', "foo")
|
13
|
+
@client.get('a_queue').should == 'foo'
|
14
|
+
end
|
15
|
+
|
16
|
+
it "unmarshals marshaled objects" do
|
17
|
+
test_object = {:a => 1, :b => [1, 2, 3]}
|
18
|
+
mock(@raw_client).get('a_queue', :raw => true) { Marshal.dump(test_object) }
|
19
|
+
@client.get('a_queue').should == test_object
|
20
|
+
end
|
21
|
+
|
22
|
+
it "does not unmarshal when raw is true" do
|
23
|
+
test_object = {:a => 1, :b => [1, 2, 3]}
|
24
|
+
mock(@raw_client).get('a_queue', :raw => true) { Marshal.dump(test_object) }
|
25
|
+
@client.get('a_queue', :raw => true).should == Marshal.dump(test_object)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "passes through objects" do
|
29
|
+
test_object = Object.new
|
30
|
+
mock(@raw_client).get('a_queue', :raw => true) { test_object }
|
31
|
+
@client.get('a_queue').should == test_object
|
32
|
+
end
|
33
|
+
|
34
|
+
it "passes through strings" do
|
35
|
+
mock(@raw_client).get('a_queue', :raw => true) { "I am not marshaled" }
|
36
|
+
@client.get('a_queue').should == "I am not marshaled"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#isMarshaled" do
|
41
|
+
it "should foo" do
|
42
|
+
@client.is_marshaled?("foo").should be_falsey
|
43
|
+
@client.is_marshaled?(Marshal.dump("foo")).should be_truthy
|
44
|
+
@client.is_marshaled?(Marshal.dump("foo")).should be_truthy
|
45
|
+
|
46
|
+
@client.is_marshaled?({}).should be_falsey
|
47
|
+
@client.is_marshaled?(Marshal.dump({})).should be_truthy
|
48
|
+
@client.is_marshaled?(Marshal.dump({})).should be_truthy
|
49
|
+
|
50
|
+
@client.is_marshaled?(BadObject.new).should be_falsey
|
51
|
+
@client.is_marshaled?(Marshal.dump(BadObject.new)).should be_truthy
|
52
|
+
@client.is_marshaled?(Marshal.dump(BadObject.new)).should be_truthy
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class BadObject
|
59
|
+
def to_s
|
60
|
+
raise Exception
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
module Marshal
|
65
|
+
def self.load_with_constantize(source, loaded_constants = [])
|
66
|
+
self.load(source)
|
67
|
+
end
|
68
|
+
end
|