right_support 2.6.17 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +4 -0
- data/CHANGELOG.rdoc +37 -0
- data/Gemfile +29 -0
- data/Gemfile.lock +111 -0
- data/README.rdoc +2 -0
- data/Rakefile +62 -0
- data/VERSION +1 -0
- data/features/balancer_error_handling.feature +34 -0
- data/features/balancer_health_check.feature +33 -0
- data/features/continuous_integration.feature +51 -0
- data/features/continuous_integration_cucumber.feature +28 -0
- data/features/continuous_integration_rspec1.feature +28 -0
- data/features/continuous_integration_rspec2.feature +28 -0
- data/features/http_client_timeout.feature +19 -0
- data/features/serialization.feature +95 -0
- data/features/step_definitions/http_client_steps.rb +27 -0
- data/features/step_definitions/request_balancer_steps.rb +93 -0
- data/features/step_definitions/ruby_steps.rb +176 -0
- data/features/step_definitions/serialization_steps.rb +96 -0
- data/features/step_definitions/server_steps.rb +134 -0
- data/features/support/env.rb +138 -0
- data/features/support/file_utils_bundler_mixin.rb +45 -0
- data/lib/right_support/ci/java_cucumber_formatter.rb +22 -8
- data/lib/right_support/ci/java_spec_formatter.rb +26 -8
- data/lib/right_support/ci/rake_task.rb +3 -0
- data/lib/right_support/ci.rb +24 -0
- data/lib/right_support/crypto/signed_hash.rb +22 -0
- data/lib/right_support/data/serializer.rb +24 -2
- data/lib/right_support/net/address_helper.rb +20 -8
- data/lib/right_support/net/dns.rb +20 -8
- data/lib/right_support/net/http_client.rb +22 -0
- data/lib/right_support/net/request_balancer.rb +27 -21
- data/lib/right_support/net/s3_helper.rb +20 -8
- data/lib/right_support/net/ssl/open_ssl_patch.rb +22 -0
- data/lib/right_support/net/ssl.rb +20 -8
- data/lib/right_support/ruby/easy_singleton.rb +22 -0
- data/lib/right_support/ruby/object_extensions.rb +22 -0
- data/lib/right_support/ruby/string_extensions.rb +1 -1
- data/lib/right_support.rb +13 -10
- data/right_support.gemspec +180 -18
- data/right_support.rconf +8 -0
- data/spec/config/feature_set_spec.rb +83 -0
- data/spec/crypto/signed_hash_spec.rb +60 -0
- data/spec/data/hash_tools_spec.rb +471 -0
- data/spec/data/uuid_spec.rb +45 -0
- data/spec/db/cassandra_model_part1_spec.rb +84 -0
- data/spec/db/cassandra_model_part2_spec.rb +73 -0
- data/spec/db/cassandra_model_spec.rb +359 -0
- data/spec/fixtures/encrypted_priv_rsa.pem +30 -0
- data/spec/fixtures/good_priv_dsa.pem +12 -0
- data/spec/fixtures/good_priv_rsa.pem +15 -0
- data/spec/fixtures/good_pub_dsa.ssh +1 -0
- data/spec/fixtures/good_pub_rsa.pem +5 -0
- data/spec/fixtures/good_pub_rsa.ssh +1 -0
- data/spec/log/exception_logger_spec.rb +76 -0
- data/spec/log/filter_logger_spec.rb +8 -0
- data/spec/log/mixin_spec.rb +62 -0
- data/spec/log/multiplexer_spec.rb +54 -0
- data/spec/log/null_logger_spec.rb +36 -0
- data/spec/log/system_logger_spec.rb +92 -0
- data/spec/net/address_helper_spec.rb +57 -0
- data/spec/net/balancing/health_check_spec.rb +382 -0
- data/spec/net/balancing/round_robin_spec.rb +15 -0
- data/spec/net/balancing/sticky_policy_spec.rb +92 -0
- data/spec/net/dns_spec.rb +152 -0
- data/spec/net/http_client_spec.rb +171 -0
- data/spec/net/request_balancer_spec.rb +579 -0
- data/spec/net/s3_helper_spec.rb +160 -0
- data/spec/net/ssl_spec.rb +42 -0
- data/spec/net/string_encoder_spec.rb +58 -0
- data/spec/rack/log_setter_spec.rb +5 -0
- data/spec/rack/request_logger_spec.rb +68 -0
- data/spec/rack/request_tracker_spec.rb +5 -0
- data/spec/ruby/easy_singleton_spec.rb +72 -0
- data/spec/ruby/object_extensions_spec.rb +27 -0
- data/spec/ruby/string_extensions_spec.rb +98 -0
- data/spec/spec_helper.rb +181 -0
- data/spec/stats/activity_spec.rb +193 -0
- data/spec/stats/exceptions_spec.rb +123 -0
- data/spec/stats/helpers_spec.rb +603 -0
- data/spec/validation/openssl_spec.rb +37 -0
- data/spec/validation/ssh_spec.rb +39 -0
- metadata +218 -19
@@ -0,0 +1,471 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module RightSupport::Data::HashToolsSpec
|
4
|
+
|
5
|
+
class BetterHash < Hash
|
6
|
+
def bells_and_whistles; true; end
|
7
|
+
end
|
8
|
+
|
9
|
+
class HashLike
|
10
|
+
def initialize; @inner_hash = {}; end
|
11
|
+
def has_key?(key); @inner_hash.has_key?(key); end
|
12
|
+
def [](key); @inner_hash[key]; end
|
13
|
+
def []=(key, value); @inner_hash[key] = value; end
|
14
|
+
def delete(key); @inner_hash.delete(key); end
|
15
|
+
def merge!(other); @inner_hash.merge!(other); self; end
|
16
|
+
def ==(other); @inner_hash == other; end
|
17
|
+
end
|
18
|
+
|
19
|
+
class DuplicableValue
|
20
|
+
def initialize(value); @value = value; end
|
21
|
+
attr_accessor :value
|
22
|
+
def duplicable?; true; end
|
23
|
+
def ==(other); other.kind_of?(DuplicableValue) && value == other.value; end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
describe RightSupport::Data::HashTools do
|
29
|
+
subject { RightSupport::Data::HashTools }
|
30
|
+
|
31
|
+
context '#hashable?' do
|
32
|
+
it 'should be true for hashes' do
|
33
|
+
subject.hashable?({}).should be_true
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should be true for hash-based objects' do
|
37
|
+
subject.hashable?(::RightSupport::Data::HashToolsSpec::BetterHash.new).should be_true
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should be true for hash-like objects' do
|
41
|
+
subject.hashable?(::RightSupport::Data::HashToolsSpec::HashLike.new).should be_true
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should be false for unhashable objects' do
|
45
|
+
subject.hashable?([1, 2, 3]).should be_false
|
46
|
+
subject.hashable?("hi there").should be_false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context '#hash_like?' do
|
51
|
+
it 'should be true for Hash' do
|
52
|
+
subject.hash_like?(::Hash).should be_true
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should be true for hash-based classes' do
|
56
|
+
subject.hash_like?(::RightSupport::Data::HashToolsSpec::BetterHash).should be_true
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should be true for hash-like classes' do
|
60
|
+
subject.hash_like?(::RightSupport::Data::HashToolsSpec::HashLike).should be_true
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should be false for non-hash classes' do
|
64
|
+
subject.hash_like?(Array).should be_false
|
65
|
+
subject.hash_like?(String).should be_false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context '#deep_get' do
|
70
|
+
hash = { 'tree' => { 'branch' => { 'leaf' => 42, 'other' => 41 },
|
71
|
+
'other' => { 'leaf' => 43 } } }
|
72
|
+
{
|
73
|
+
:valid_leaf => {
|
74
|
+
:path => ['tree', 'branch', 'leaf'],
|
75
|
+
:expected => 42 },
|
76
|
+
:valid_other_leaf => {
|
77
|
+
:path => ['tree', 'branch', 'other'],
|
78
|
+
:expected => 41 },
|
79
|
+
:valid_branch => {
|
80
|
+
:path => ['tree', 'branch'],
|
81
|
+
:expected => { 'leaf' => 42, 'other' => 41 } },
|
82
|
+
:valid_other_branch => {
|
83
|
+
:path => ['tree', 'other'],
|
84
|
+
:expected => { 'leaf' => 43 } },
|
85
|
+
:invalid_leaf => {
|
86
|
+
:path => ['tree', 'branch', 'leaf', 'bogus'],
|
87
|
+
:expected => nil },
|
88
|
+
:invalid_branch => {
|
89
|
+
:path => ['tree', 'bogus'],
|
90
|
+
:expected => nil },
|
91
|
+
:nil => {
|
92
|
+
:path => nil,
|
93
|
+
:expected => nil },
|
94
|
+
:empty => {
|
95
|
+
:path => [],
|
96
|
+
:expected => nil }
|
97
|
+
}.each do |kind, data|
|
98
|
+
it "should deep get #{kind} paths" do
|
99
|
+
actual = subject.deep_get(hash, data[:path])
|
100
|
+
actual.should == data[:expected]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context '#deep_set!' do
|
106
|
+
{
|
107
|
+
:empty => {
|
108
|
+
:target => {},
|
109
|
+
:path => ['tree', 'branch', 'leaf'],
|
110
|
+
:value => 42,
|
111
|
+
:expected => { 'tree' => { 'branch' => { 'leaf' => 42 } } } },
|
112
|
+
:identical_structure => {
|
113
|
+
:target => { 'tree' => { 'branch' => { 'leaf' => 42 } } },
|
114
|
+
:path => ['tree', 'branch', 'leaf'],
|
115
|
+
:value => 41,
|
116
|
+
:expected => { 'tree' => { 'branch' => { 'leaf' => 41 } } } },
|
117
|
+
:similar_structure => {
|
118
|
+
:target => { 'tree' => { 'branch' => { 'other' => 41 } } },
|
119
|
+
:path => ['tree', 'branch', 'leaf'],
|
120
|
+
:value => 42,
|
121
|
+
:expected => { 'tree' => { 'branch' => { 'leaf' => 42, 'other' => 41 } } } },
|
122
|
+
:different_hash_subclass => {
|
123
|
+
:target => {},
|
124
|
+
:path => ['tree', 'branch', 'leaf'],
|
125
|
+
:value => 42,
|
126
|
+
:clazz => ::RightSupport::Data::HashToolsSpec::BetterHash,
|
127
|
+
:expected => { 'tree' => { 'branch' => { 'leaf' => 42 } } } },
|
128
|
+
:different_hash_like_class => {
|
129
|
+
:target => {},
|
130
|
+
:path => ['tree', 'branch', 'leaf'],
|
131
|
+
:value => 42,
|
132
|
+
:clazz => ::RightSupport::Data::HashToolsSpec::HashLike,
|
133
|
+
:expected => { 'tree' => { 'branch' => { 'leaf' => 42 } } } }
|
134
|
+
}.each do |kind, data|
|
135
|
+
it "should deep set values in #{kind} hashes" do
|
136
|
+
subject.deep_set!(data[:target], data[:path], data[:value], data[:clazz])
|
137
|
+
data[:target].should == data[:expected]
|
138
|
+
expected_class = data[:clazz] || data[:target].class
|
139
|
+
data[:target].values.first.class.should == expected_class
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context '#deep_clone' do
|
145
|
+
def deep_check_object_id(a, b, &leaf_callback)
|
146
|
+
a.object_id.should_not == b.object_id
|
147
|
+
a.each do |k, v|
|
148
|
+
if subject.hashable?(v)
|
149
|
+
deep_check_object_id(v, b[k])
|
150
|
+
elsif leaf_callback
|
151
|
+
leaf_callback.call(v, b[k])
|
152
|
+
elsif v.respond_to?(:duplicable?) && v.duplicable?
|
153
|
+
v.object_id.should_not == b[k].object_id
|
154
|
+
else
|
155
|
+
v.object_id.should == b[k].object_id
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
{
|
161
|
+
:empty => {},
|
162
|
+
:shallow => { :x => 1, :y => 2 },
|
163
|
+
:deep => { :x => 1, :y => { :a => 'A' }, :z => { :b => 'B', :c => { :foo => :bar }} },
|
164
|
+
:duplicable => {
|
165
|
+
:tree => {
|
166
|
+
:branch => {
|
167
|
+
:a => ::RightSupport::Data::HashToolsSpec::DuplicableValue.new(1),
|
168
|
+
:b => ::RightSupport::Data::HashToolsSpec::DuplicableValue.new('hi there') } } }
|
169
|
+
}.each do |kind, data|
|
170
|
+
it "should deep clone values in #{kind} hashes" do
|
171
|
+
actual = subject.deep_clone(data)
|
172
|
+
actual.should == data
|
173
|
+
if :duplicable == kind
|
174
|
+
# verify that leaves are duplicable
|
175
|
+
data[:tree][:branch][:a].duplicable?.should be_true
|
176
|
+
data[:tree][:branch][:b].duplicable?.should be_true
|
177
|
+
end
|
178
|
+
deep_check_object_id(actual, data)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'should deep clone leaves using callback when given' do
|
183
|
+
initial = { :x => 1, :y => { :a => [1, 2, 3], :b => [4, 5, 6] } }
|
184
|
+
actual = subject.deep_clone(initial) { |value| value.kind_of?(Array) ? value.clone : value }
|
185
|
+
actual.should == initial
|
186
|
+
deep_check_object_id(actual, initial) do |a, b|
|
187
|
+
if a.kind_of?(Array)
|
188
|
+
a.object_id.should_not == b.object_id
|
189
|
+
else
|
190
|
+
a.object_id.should == b.object_id
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
context '#deep_merge!' do
|
197
|
+
{
|
198
|
+
:identical => {
|
199
|
+
:left => { :one => 1 },
|
200
|
+
:right => { :one => 1 },
|
201
|
+
:expected => { :one => 1 } },
|
202
|
+
:disjoint => {
|
203
|
+
:left => { :one => 1 },
|
204
|
+
:right => { :two => 1 },
|
205
|
+
:expected => { :one => 1, :two => 1 } },
|
206
|
+
:value_diff => {
|
207
|
+
:left => { :one => 1 },
|
208
|
+
:right => { :one => 2 },
|
209
|
+
:expected => { :one => 2 } },
|
210
|
+
:recursive_disjoint => {
|
211
|
+
:left => { :one => { :a => 1, :b => 2 }, :two => 3 },
|
212
|
+
:right => { :one => { :a => 1 }, :two => 3 },
|
213
|
+
:expected => { :one => { :a => 1, :b => 2 }, :two => 3 } },
|
214
|
+
:recursive_value_diff => {
|
215
|
+
:left => { :one => { :a => 1, :b => 2 }, :two => 3 },
|
216
|
+
:right => { :one => { :a => 1, :b => 3 }, :two => 3 },
|
217
|
+
:expected => { :one => { :a => 1, :b => 3 }, :two => 3 } },
|
218
|
+
:recursive_disjoint_and_value_diff => {
|
219
|
+
:left => { :one => { :a => 1, :b => 2, :c => 3 }, :two => 3, :three => 4 },
|
220
|
+
:right => { :one => { :a => 1, :b => 3, :d => 4 }, :two => 5, :four => 6 },
|
221
|
+
:expected => { :one => { :a => 1, :b => 3, :c => 3 , :d => 4 }, :two => 5, :three => 4, :four => 6 } }
|
222
|
+
}.each do |kind, data|
|
223
|
+
it "should deep merge #{kind} hashes" do
|
224
|
+
actual = subject.deep_merge!(data[:left], data[:right])
|
225
|
+
actual.should == data[:expected]
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
context "#deep_remove!" do
|
231
|
+
{
|
232
|
+
:empty => {
|
233
|
+
:target => {},
|
234
|
+
:source => {},
|
235
|
+
:expected => {} },
|
236
|
+
:identical => {
|
237
|
+
:target => { :x => 1, :y => { :foo => :bar } },
|
238
|
+
:source => { :x => 1, :y => { :foo => :bar } },
|
239
|
+
:expected => {} },
|
240
|
+
:greater_target => {
|
241
|
+
:target => { :x => 1, :y => { :a => 'a', :b => 'b' } },
|
242
|
+
:source => { :x => 1, :y => { :a => 'a' } },
|
243
|
+
:expected => { :y => { :b => 'b' } } },
|
244
|
+
:greater_source => {
|
245
|
+
:target => { :x => 1, :y => { :a => 'a' } },
|
246
|
+
:source => { :x => 1, :y => { :a => 'a', :b => 'b' } },
|
247
|
+
:expected => { :y => {} } },
|
248
|
+
:disjoint => {
|
249
|
+
:target => { :x => 1, :y => { :a => 'a' } },
|
250
|
+
:source => { :x => 2, :y => { :b => 'b' } },
|
251
|
+
:expected => { :x => 1, :y => { :a => 'a' } } }
|
252
|
+
}.each do |kind, data|
|
253
|
+
it "should deep remove values from #{kind} hashes" do
|
254
|
+
actual = subject.deep_remove!(data[:target], data[:source])
|
255
|
+
actual.should == data[:expected]
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
context "#deep_create_patch" do
|
261
|
+
{
|
262
|
+
:identical => {
|
263
|
+
:left => { :one => 1 },
|
264
|
+
:right => { :one => 1 },
|
265
|
+
:expected => { :left_only => {},
|
266
|
+
:right_only => {},
|
267
|
+
:diff => {} } },
|
268
|
+
:disjoint => {
|
269
|
+
:left => { :one => 1 },
|
270
|
+
:right => { :two => 1 },
|
271
|
+
:expected => { :left_only => { :one => 1},
|
272
|
+
:right_only => { :two => 1},
|
273
|
+
:diff => {} }
|
274
|
+
},
|
275
|
+
:value_diff => {
|
276
|
+
:left => { :one => 1 },
|
277
|
+
:right => { :one => 2 },
|
278
|
+
:expected => { :left_only => {},
|
279
|
+
:right_only => {},
|
280
|
+
:diff => { :one => { :left => 1, :right => 2} } } },
|
281
|
+
:recursive_disjoint => {
|
282
|
+
:left => { :one => { :a => 1, :b => 2 }, :two => 3 },
|
283
|
+
:right => { :one => { :a => 1 }, :two => 3 },
|
284
|
+
:expected => { :left_only => { :one => { :b => 2 }},
|
285
|
+
:right_only => {},
|
286
|
+
:diff => {} } },
|
287
|
+
:recursive_value_diff => {
|
288
|
+
:left => { :one => { :a => 1, :b => 2 }, :two => 3 },
|
289
|
+
:right => { :one => { :a => 1, :b => 3 }, :two => 3 },
|
290
|
+
:expected => { :left_only => {},
|
291
|
+
:right_only => {},
|
292
|
+
:diff => { :one => { :b => { :left => 2, :right => 3 }} } } },
|
293
|
+
:recursive_disjoint_and_value_diff => {
|
294
|
+
:left => { :one => { :a => 1, :b => 2, :c => 3 }, :two => 3, :three => 4 },
|
295
|
+
:right => { :one => { :a => 1, :b => 3, :d => 4 }, :two => 5, :four => 6 },
|
296
|
+
:expected => { :left_only => { :one => { :c => 3 }, :three => 4 },
|
297
|
+
:right_only => { :one => { :d => 4 }, :four => 6 },
|
298
|
+
:diff => { :one => { :b => { :left => 2, :right => 3 }}, :two => { :left => 3, :right => 5 } } } }
|
299
|
+
}.each do |kind, data|
|
300
|
+
it "should deep create patch for #{kind} hashes" do
|
301
|
+
actual = subject.deep_create_patch(data[:left], data[:right])
|
302
|
+
actual.should == data[:expected]
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
context '#deep_apply_patch!' do
|
308
|
+
{
|
309
|
+
:empty_patch => {
|
310
|
+
:target => { :one => 1 },
|
311
|
+
:patch => { :left_only => {}, :right_only => {}, :diff => {} },
|
312
|
+
:expected => { :one => 1 } },
|
313
|
+
:disjoint => {
|
314
|
+
:target => { :one => 1 },
|
315
|
+
:patch => { :left_only => { :one => 2 }, :right_only => {}, :diff => { :one => { :left => 3, :right => 4 } } },
|
316
|
+
:expected => { :one => 1 } },
|
317
|
+
:removal => {
|
318
|
+
:target => { :one => 1 },
|
319
|
+
:patch => { :left_only => { :one => 1 }, :right_only => {}, :diff => {} },
|
320
|
+
:expected => {} },
|
321
|
+
:addition => {
|
322
|
+
:target => { :one => 1 },
|
323
|
+
:patch => { :left_only => {}, :right_only => { :two => 2 }, :diff => {} },
|
324
|
+
:expected => { :one => 1, :two => 2 } },
|
325
|
+
:substitution => {
|
326
|
+
:target => { :one => 1 },
|
327
|
+
:patch => { :left_only => {}, :right_only => {}, :diff => { :one => { :left => 1, :right => 2 } } },
|
328
|
+
:expected => { :one => 2 } },
|
329
|
+
:recursive_removal => {
|
330
|
+
:target => { :one => { :a => 1, :b => 2 } },
|
331
|
+
:patch => { :left_only => { :one => { :a => 1 }}, :right_only => {}, :diff => {} },
|
332
|
+
:expected => { :one => { :b => 2 } } },
|
333
|
+
:recursive_addition => {
|
334
|
+
:target => { :one => { :a => 1 } },
|
335
|
+
:patch => { :left_only => {}, :right_only => { :one => { :b => 2 } }, :diff => {} },
|
336
|
+
:expected => { :one => { :a => 1, :b => 2 } } },
|
337
|
+
:recursive_substitution => {
|
338
|
+
:target => { :one => { :a => 1 } },
|
339
|
+
:patch => { :left_only => {}, :right_only => {}, :diff => { :one => { :a => { :left => 1, :right => 2 } } } },
|
340
|
+
:expected => { :one => { :a => 2 } } },
|
341
|
+
:combined => {
|
342
|
+
:target => { :one => { :a => 1, :b => 2 } },
|
343
|
+
:patch => { :left_only => { :one => { :a => 1 } }, :right_only => { :one => { :c => 3 }}, :diff => { :one => { :b => { :left => 2, :right => 3 } } } },
|
344
|
+
:expected => { :one => { :b => 3, :c => 3 } } }
|
345
|
+
}.each do |kind, data|
|
346
|
+
it "should deep apply #{kind} patches" do
|
347
|
+
actual = subject.deep_apply_patch!(data[:target], data[:patch])
|
348
|
+
actual.should == data[:expected]
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
context '#deep_sorted_json' do
|
354
|
+
|
355
|
+
let(:flat_hash) do
|
356
|
+
result = {}
|
357
|
+
10.times do |i|
|
358
|
+
# try to ensure insertion order does not affect the unsorted extraction
|
359
|
+
# order by inserting keys out-of-order. insertion order historically has
|
360
|
+
# no affect on extraction order, but you never know about future Hash.
|
361
|
+
# if the Hash of tomorrow is always sorted, then goody.
|
362
|
+
i = (13 - i) % 10
|
363
|
+
key = (i + ?a.ord).chr
|
364
|
+
key = key.to_sym if 0 == (i % 2) # every other key is a symbol
|
365
|
+
result[key] = i
|
366
|
+
end
|
367
|
+
result
|
368
|
+
end
|
369
|
+
|
370
|
+
let(:deep_hash) do
|
371
|
+
result = {}
|
372
|
+
result['y'] = flat_hash.dup
|
373
|
+
result['y'][:z] = flat_hash.dup
|
374
|
+
result[:x] = flat_hash.dup
|
375
|
+
result.merge!(flat_hash)
|
376
|
+
result
|
377
|
+
end
|
378
|
+
|
379
|
+
it 'should produce sorted json from a flat hash' do
|
380
|
+
expected = "{\"a\":0,\"b\":1,\"c\":2,\"d\":3,\"e\":4,\"f\":5,\"g\":6,\"h\":7,\"i\":8,\"j\":9}"
|
381
|
+
actual = subject.deep_sorted_json(flat_hash)
|
382
|
+
actual.should == expected
|
383
|
+
end
|
384
|
+
|
385
|
+
it 'should produce pretty sorted json from a flat hash' do
|
386
|
+
expected = <<EOF
|
387
|
+
{
|
388
|
+
"a": 0,
|
389
|
+
"b": 1,
|
390
|
+
"c": 2,
|
391
|
+
"d": 3,
|
392
|
+
"e": 4,
|
393
|
+
"f": 5,
|
394
|
+
"g": 6,
|
395
|
+
"h": 7,
|
396
|
+
"i": 8,
|
397
|
+
"j": 9
|
398
|
+
}
|
399
|
+
EOF
|
400
|
+
expected = expected.strip
|
401
|
+
actual = subject.deep_sorted_json(flat_hash, pretty=true)
|
402
|
+
actual.should == expected
|
403
|
+
end
|
404
|
+
|
405
|
+
it 'should produce sorted json from a deep hash' do
|
406
|
+
expected = "{\"a\":0,\"b\":1,\"c\":2,\"d\":3,\"e\":4,\"f\":5,\"g\":6,\"h\":7,\"i\":8,\"j\":9," +
|
407
|
+
"\"x\":{\"a\":0,\"b\":1,\"c\":2,\"d\":3,\"e\":4,\"f\":5,\"g\":6,\"h\":7,\"i\":8,\"j\":9}," +
|
408
|
+
"\"y\":{\"a\":0,\"b\":1,\"c\":2,\"d\":3,\"e\":4,\"f\":5,\"g\":6,\"h\":7,\"i\":8,\"j\":9," +
|
409
|
+
"\"z\":{\"a\":0,\"b\":1,\"c\":2,\"d\":3,\"e\":4,\"f\":5,\"g\":6,\"h\":7,\"i\":8,\"j\":9}}}"
|
410
|
+
actual = subject.deep_sorted_json(deep_hash)
|
411
|
+
actual.should == expected
|
412
|
+
end
|
413
|
+
|
414
|
+
it 'should produce pretty sorted json from a deep hash' do
|
415
|
+
expected = <<EOF
|
416
|
+
{
|
417
|
+
"a": 0,
|
418
|
+
"b": 1,
|
419
|
+
"c": 2,
|
420
|
+
"d": 3,
|
421
|
+
"e": 4,
|
422
|
+
"f": 5,
|
423
|
+
"g": 6,
|
424
|
+
"h": 7,
|
425
|
+
"i": 8,
|
426
|
+
"j": 9,
|
427
|
+
"x": {
|
428
|
+
"a": 0,
|
429
|
+
"b": 1,
|
430
|
+
"c": 2,
|
431
|
+
"d": 3,
|
432
|
+
"e": 4,
|
433
|
+
"f": 5,
|
434
|
+
"g": 6,
|
435
|
+
"h": 7,
|
436
|
+
"i": 8,
|
437
|
+
"j": 9
|
438
|
+
},
|
439
|
+
"y": {
|
440
|
+
"a": 0,
|
441
|
+
"b": 1,
|
442
|
+
"c": 2,
|
443
|
+
"d": 3,
|
444
|
+
"e": 4,
|
445
|
+
"f": 5,
|
446
|
+
"g": 6,
|
447
|
+
"h": 7,
|
448
|
+
"i": 8,
|
449
|
+
"j": 9,
|
450
|
+
"z": {
|
451
|
+
"a": 0,
|
452
|
+
"b": 1,
|
453
|
+
"c": 2,
|
454
|
+
"d": 3,
|
455
|
+
"e": 4,
|
456
|
+
"f": 5,
|
457
|
+
"g": 6,
|
458
|
+
"h": 7,
|
459
|
+
"i": 8,
|
460
|
+
"j": 9
|
461
|
+
}
|
462
|
+
}
|
463
|
+
}
|
464
|
+
EOF
|
465
|
+
expected = expected.strip
|
466
|
+
actual = subject.deep_sorted_json(deep_hash, pretty=true)
|
467
|
+
actual.should == expected
|
468
|
+
end
|
469
|
+
|
470
|
+
end
|
471
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RightSupport::Data::UUID do
|
4
|
+
subject { RightSupport::Data::UUID }
|
5
|
+
|
6
|
+
VALID_UUID = /[0-9a-f-]+/ #we're not too picky here...
|
7
|
+
|
8
|
+
context :generate do
|
9
|
+
context 'when no implementation is available' do
|
10
|
+
it 'raises Unavailable' do
|
11
|
+
flexmock(subject).should_receive(:implementation).and_return(nil)
|
12
|
+
lambda {
|
13
|
+
subject.generate
|
14
|
+
}.should raise_error(subject::Unavailable)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when SimpleUUID is available' do
|
19
|
+
it 'generates UUIDs' do
|
20
|
+
subject.implementation = subject::SimpleUUID
|
21
|
+
subject.generate.should =~ VALID_UUID
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when UUIDTools v1 is available' do
|
26
|
+
it 'generates UUIDs' do
|
27
|
+
pending #need to rework tests to test 2 versions of 1 gem!
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when UUIDTools v2 is available' do
|
32
|
+
it 'generates UUIDs' do
|
33
|
+
subject.implementation = subject::UUIDTools2
|
34
|
+
subject.generate.should =~ VALID_UUID
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when UUID gem is available' do
|
39
|
+
it 'generates UUIDs' do
|
40
|
+
subject.implementation = subject::UUIDGem
|
41
|
+
subject.generate.should =~ VALID_UUID
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RightSupport::DB::CassandraModel do
|
4
|
+
|
5
|
+
class Cassandra
|
6
|
+
class OrderedHash < Hash
|
7
|
+
def keys
|
8
|
+
super.sort
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "config" do
|
14
|
+
let(:config) { {'test' => {'server' => 'connection'} \
|
15
|
+
,'developemnt' => {'server' => 'connection1'}} }
|
16
|
+
|
17
|
+
['test', 'developemnt'].each do |env|
|
18
|
+
it "should return correct env: #{env.inspect} config" do
|
19
|
+
RightSupport::DB::CassandraModel.config = config
|
20
|
+
old_rack_env = ENV['RACK_ENV']
|
21
|
+
ENV['RACK_ENV'] = env
|
22
|
+
config[env].should == RightSupport::DB::CassandraModel.env_config
|
23
|
+
ENV['RACK_ENV'] = old_rack_env
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should raise error if config not set or not Hash" do
|
28
|
+
old_rack_env = ENV['RACK_ENV']
|
29
|
+
RightSupport::DB::CassandraModel.config = nil
|
30
|
+
ENV['RACK_ENV'] = 'nil_config'
|
31
|
+
lambda {
|
32
|
+
RightSupport::DB::CassandraModel.env_config
|
33
|
+
}.should raise_error RightSupport::DB::MissingConfiguration
|
34
|
+
|
35
|
+
ENV['RACK_ENV'] = old_rack_env
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should raise error if no configuration find" do
|
39
|
+
RightSupport::DB::CassandraModel.config = config
|
40
|
+
old_rack_env = ENV['RACK_ENV']
|
41
|
+
ENV['RACK_ENV'] = 'super_environment'
|
42
|
+
lambda {
|
43
|
+
RightSupport::DB::CassandraModel.env_config
|
44
|
+
}.should raise_error RightSupport::DB::MissingConfiguration
|
45
|
+
ENV['RACK_ENV'] = old_rack_env
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
context "initialize" do
|
51
|
+
let(:env) { 'server_config' }
|
52
|
+
let(:column_family) { 'server_config_column_family' }
|
53
|
+
let(:default_keyspace) { 'ServerConfigSatelliteService' }
|
54
|
+
let(:default_keyspace_connection) { flexmock('cassandra') }
|
55
|
+
|
56
|
+
{
|
57
|
+
'[ring1, ring2, ring3]' => ['ring1', 'ring2', 'ring3'] \
|
58
|
+
,'ring1, ring2, ring3' => ['ring1', 'ring2', 'ring3'] \
|
59
|
+
,['ring1', 'ring2', 'ring3'] => ['ring1', 'ring2', 'ring3']
|
60
|
+
}.each do |config_string, congig_test|
|
61
|
+
it "shoudl successfully intialize from #{config_string.inspect}" do
|
62
|
+
|
63
|
+
|
64
|
+
old_rack_env = ENV['RACK_ENV']
|
65
|
+
begin
|
66
|
+
ENV['RACK_ENV'] = env
|
67
|
+
|
68
|
+
flexmock(Cassandra).should_receive(:new).with(default_keyspace + '_' + env, congig_test , {:timeout=>10}).and_return(default_keyspace_connection)
|
69
|
+
default_keyspace_connection.should_receive(:disable_node_auto_discovery!).and_return(true)
|
70
|
+
|
71
|
+
|
72
|
+
RightSupport::DB::CassandraModel.config = {env => {"server" => config_string}}
|
73
|
+
RightSupport::DB::CassandraModel.keyspace = default_keyspace
|
74
|
+
RightSupport::DB::CassandraModel.reconnect
|
75
|
+
|
76
|
+
ensure
|
77
|
+
ENV['RACK_ENV'] = old_rack_env
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RightSupport::DB::CassandraModel do
|
4
|
+
|
5
|
+
class Cassandra
|
6
|
+
class OrderedHash < Hash
|
7
|
+
def keys
|
8
|
+
super.sort
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "do_op() logging" do
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
@logger = flexmock(:logger)
|
17
|
+
flexmock(RightSupport::Log::Mixin).should_receive(:default_logger).and_return(@logger)
|
18
|
+
@logger.should_receive(:debug).with(String)
|
19
|
+
@conn = flexmock(:connection)
|
20
|
+
flexmock(RightSupport::DB::CassandraModel).should_receive(:conn).and_return(@conn)
|
21
|
+
@conn.should_receive(:multi_get).and_return(true)
|
22
|
+
@conn.should_receive(:get).and_return(true)
|
23
|
+
@conn.should_receive(:get_indexed_slices).and_return(true)
|
24
|
+
@conn.should_receive(:get_columns).and_return(true)
|
25
|
+
@conn.should_receive(:insert).and_return(true)
|
26
|
+
@conn.should_receive(:remove).and_return(true)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "logs requests" do
|
30
|
+
[:multi_get, :get, :get_indexed_slices, :get_columns, :insert, :remove].each do |method|
|
31
|
+
RightSupport::DB::CassandraModel.do_op(method,'test_column_family', 'test_key')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
context "do_op_log" do
|
38
|
+
before(:each) do
|
39
|
+
@logger = flexmock(:logger)
|
40
|
+
flexmock(RightSupport::Log::Mixin).should_receive(:default_logger).and_return(@logger)
|
41
|
+
flexmock(Time).should_receive(:now).and_return(100.010)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should display size for the keys if they are array" do
|
45
|
+
first_started_at = 100.0
|
46
|
+
started_at = 100.0
|
47
|
+
@logger.should_receive(:debug).with("CassandraModel get, cf=cf_name, keys=5, time=10.0ms")
|
48
|
+
RightSupport::DB::CassandraModel.do_op_log(first_started_at, started_at, 0, :get, 'cf_name', [1,2,3,4,5])
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should display size for the key equal 1 if not array" do
|
52
|
+
first_started_at = 100.0
|
53
|
+
started_at = 100.0
|
54
|
+
@logger.should_receive(:debug).with("CassandraModel get, cf=cf_name, keys=1, time=10.0ms")
|
55
|
+
RightSupport::DB::CassandraModel.do_op_log(first_started_at, started_at, 0, :get, 'cf_name', "10")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should display attemps time in milliseconds (ms)" do
|
59
|
+
first_started_at = 100.0
|
60
|
+
started_at = 100.0
|
61
|
+
@logger.should_receive(:debug).with("CassandraModel get, cf=cf_name, keys=1, time=10.0ms")
|
62
|
+
RightSupport::DB::CassandraModel.do_op_log(first_started_at, started_at, 0, :get, 'cf_name', [11])
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should display total time milliseconds (s)" do
|
66
|
+
first_started_at = 99.0
|
67
|
+
started_at = 100.0
|
68
|
+
@logger.should_receive(:debug).with("CassandraModel get, cf=cf_name, keys=1, time=10.0ms, retries=1, total_time=1010.0ms")
|
69
|
+
RightSupport::DB::CassandraModel.do_op_log(first_started_at, started_at, 1, :get, 'cf_name', [11])
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|