right_support 2.6.17 → 2.7.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.
Files changed (83) hide show
  1. data/.rspec +4 -0
  2. data/CHANGELOG.rdoc +37 -0
  3. data/Gemfile +29 -0
  4. data/Gemfile.lock +111 -0
  5. data/README.rdoc +2 -0
  6. data/Rakefile +62 -0
  7. data/VERSION +1 -0
  8. data/features/balancer_error_handling.feature +34 -0
  9. data/features/balancer_health_check.feature +33 -0
  10. data/features/continuous_integration.feature +51 -0
  11. data/features/continuous_integration_cucumber.feature +28 -0
  12. data/features/continuous_integration_rspec1.feature +28 -0
  13. data/features/continuous_integration_rspec2.feature +28 -0
  14. data/features/http_client_timeout.feature +19 -0
  15. data/features/serialization.feature +95 -0
  16. data/features/step_definitions/http_client_steps.rb +27 -0
  17. data/features/step_definitions/request_balancer_steps.rb +93 -0
  18. data/features/step_definitions/ruby_steps.rb +176 -0
  19. data/features/step_definitions/serialization_steps.rb +96 -0
  20. data/features/step_definitions/server_steps.rb +134 -0
  21. data/features/support/env.rb +138 -0
  22. data/features/support/file_utils_bundler_mixin.rb +45 -0
  23. data/lib/right_support/ci/java_cucumber_formatter.rb +22 -8
  24. data/lib/right_support/ci/java_spec_formatter.rb +26 -8
  25. data/lib/right_support/ci/rake_task.rb +3 -0
  26. data/lib/right_support/ci.rb +24 -0
  27. data/lib/right_support/crypto/signed_hash.rb +22 -0
  28. data/lib/right_support/data/serializer.rb +24 -2
  29. data/lib/right_support/net/address_helper.rb +20 -8
  30. data/lib/right_support/net/dns.rb +20 -8
  31. data/lib/right_support/net/http_client.rb +22 -0
  32. data/lib/right_support/net/request_balancer.rb +27 -21
  33. data/lib/right_support/net/s3_helper.rb +20 -8
  34. data/lib/right_support/net/ssl/open_ssl_patch.rb +22 -0
  35. data/lib/right_support/net/ssl.rb +20 -8
  36. data/lib/right_support/ruby/easy_singleton.rb +22 -0
  37. data/lib/right_support/ruby/object_extensions.rb +22 -0
  38. data/lib/right_support/ruby/string_extensions.rb +1 -1
  39. data/lib/right_support.rb +13 -10
  40. data/right_support.gemspec +180 -18
  41. data/right_support.rconf +8 -0
  42. data/spec/config/feature_set_spec.rb +83 -0
  43. data/spec/crypto/signed_hash_spec.rb +60 -0
  44. data/spec/data/hash_tools_spec.rb +471 -0
  45. data/spec/data/uuid_spec.rb +45 -0
  46. data/spec/db/cassandra_model_part1_spec.rb +84 -0
  47. data/spec/db/cassandra_model_part2_spec.rb +73 -0
  48. data/spec/db/cassandra_model_spec.rb +359 -0
  49. data/spec/fixtures/encrypted_priv_rsa.pem +30 -0
  50. data/spec/fixtures/good_priv_dsa.pem +12 -0
  51. data/spec/fixtures/good_priv_rsa.pem +15 -0
  52. data/spec/fixtures/good_pub_dsa.ssh +1 -0
  53. data/spec/fixtures/good_pub_rsa.pem +5 -0
  54. data/spec/fixtures/good_pub_rsa.ssh +1 -0
  55. data/spec/log/exception_logger_spec.rb +76 -0
  56. data/spec/log/filter_logger_spec.rb +8 -0
  57. data/spec/log/mixin_spec.rb +62 -0
  58. data/spec/log/multiplexer_spec.rb +54 -0
  59. data/spec/log/null_logger_spec.rb +36 -0
  60. data/spec/log/system_logger_spec.rb +92 -0
  61. data/spec/net/address_helper_spec.rb +57 -0
  62. data/spec/net/balancing/health_check_spec.rb +382 -0
  63. data/spec/net/balancing/round_robin_spec.rb +15 -0
  64. data/spec/net/balancing/sticky_policy_spec.rb +92 -0
  65. data/spec/net/dns_spec.rb +152 -0
  66. data/spec/net/http_client_spec.rb +171 -0
  67. data/spec/net/request_balancer_spec.rb +579 -0
  68. data/spec/net/s3_helper_spec.rb +160 -0
  69. data/spec/net/ssl_spec.rb +42 -0
  70. data/spec/net/string_encoder_spec.rb +58 -0
  71. data/spec/rack/log_setter_spec.rb +5 -0
  72. data/spec/rack/request_logger_spec.rb +68 -0
  73. data/spec/rack/request_tracker_spec.rb +5 -0
  74. data/spec/ruby/easy_singleton_spec.rb +72 -0
  75. data/spec/ruby/object_extensions_spec.rb +27 -0
  76. data/spec/ruby/string_extensions_spec.rb +98 -0
  77. data/spec/spec_helper.rb +181 -0
  78. data/spec/stats/activity_spec.rb +193 -0
  79. data/spec/stats/exceptions_spec.rb +123 -0
  80. data/spec/stats/helpers_spec.rb +603 -0
  81. data/spec/validation/openssl_spec.rb +37 -0
  82. data/spec/validation/ssh_spec.rb +39 -0
  83. 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