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.
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