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,359 @@
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
+ def init_app_state(column_family,keyspace,server,env)
14
+ ENV["RACK_ENV"] = env
15
+ RightSupport::DB::CassandraModel.column_family = column_family
16
+ RightSupport::DB::CassandraModel.keyspace = keyspace
17
+ RightSupport::DB::CassandraModel.config = {"#{env}" => {"server" => server}}
18
+ end
19
+
20
+ context "initialization" do
21
+ # This method determines the current keyspace based on the return value of the CassandraModel.keyspace method
22
+ # which looks at the value of @@current_keyspace or @@default_keyspace to determine the keyspace it is operating
23
+ # under. If a connection already exists for the keyspace it will re-use it. If a connection does not exist,
24
+ # it will create a new persistent connection for that keyspace that can be re-used with future requests
25
+ context :conn do
26
+ let(:column_family) { 'column_family' }
27
+ let(:env) { 'test' }
28
+ let(:server) { 'localhost:9160' }
29
+ let(:keyspace) { 'SatelliteService_1' }
30
+ let(:default_keyspace) { 'SatelliteService' }
31
+ let(:current_keyspace_connection) { flexmock('cassandra') }
32
+ let(:default_keyspace_connection) { flexmock('cassandra') }
33
+
34
+ before(:each) do
35
+ ENV["RACK_ENV"] = env
36
+ RightSupport::DB::CassandraModel.column_family = column_family
37
+ RightSupport::DB::CassandraModel.keyspace = default_keyspace
38
+ RightSupport::DB::CassandraModel.config = {env => {"server" => server}}
39
+
40
+ current_keyspace_connection.should_receive(:disable_node_auto_discovery!).and_return(true)
41
+ current_keyspace_connection.should_receive(:name).and_return('connection1')
42
+
43
+ default_keyspace_connection.should_receive(:disable_node_auto_discovery!).and_return(true)
44
+ default_keyspace_connection.should_receive(:name).and_return('connection2')
45
+
46
+ flexmock(Cassandra).should_receive(:new).with(keyspace + '_' + (ENV['RACK_ENV'] || 'development'), "localhost:9160", {:timeout=>10}).and_return(current_keyspace_connection)
47
+ flexmock(Cassandra).should_receive(:new).with(default_keyspace + '_' + (ENV['RACK_ENV'] || 'development'), "localhost:9160", {:timeout=>10}).and_return(default_keyspace_connection)
48
+ end
49
+
50
+ it 'raises a meaningful exception when a config stanza is missing' do
51
+ old_rack_env = ENV['RACK_ENV']
52
+
53
+ begin
54
+ ENV['RACK_ENV'] = 'foobar_12345'
55
+ bad_proc = lambda { RightSupport::DB::CassandraModel.reconnect }
56
+ bad_proc.should raise_error(RightSupport::DB::MissingConfiguration)
57
+ # This must be the very first attempt to call #conn during the execution of this spec
58
+ bad_proc = lambda { RightSupport::DB::CassandraModel.conn }
59
+ bad_proc.should raise_error(RightSupport::DB::MissingConfiguration)
60
+ ensure
61
+ ENV['RACK_ENV'] = old_rack_env
62
+ end
63
+ end
64
+
65
+ # This method assumes that keyspaces being requested to connect to already exist.
66
+ # If they do not exist, it should NOT create them. If the connection is able
67
+ # to be successfully established then it should be stored in a pool of connections
68
+ it 'creates a new connection if no connection exists for provided keyspace' do
69
+ RightSupport::DB::CassandraModel.conn.name.should == default_keyspace_connection.name
70
+ end
71
+
72
+ # If a connection has already been opened for a keyspace it should be re-used
73
+ it 're-uses an existing connection if it exists for provided keyspace' do
74
+ RightSupport::DB::CassandraModel.conn.name.should == RightSupport::DB::CassandraModel.conn.name
75
+ end
76
+
77
+ # The keyspace being used for the connection should be either the current keyspace or the default keyspace
78
+ it 'uses the connection that corresponds to the provided keyspace' do
79
+ RightSupport::DB::CassandraModel.with_keyspace(keyspace) do
80
+ RightSupport::DB::CassandraModel.conn.name.should == current_keyspace_connection.name
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ context "use" do
87
+
88
+ before(:each) do
89
+ @column_family = "TestApp"
90
+ @keyspace = "TestAppService"
91
+ @server = "localhost:9160"
92
+ @env = "test"
93
+ @timeout = {:timeout => RightSupport::DB::CassandraModel::DEFAULT_TIMEOUT}
94
+
95
+ init_app_state(@column_family, @keyspace, @server, @env)
96
+
97
+ @key = 'key'
98
+ @value = 'foo'
99
+ @offset = 'bar'
100
+ @attrs = {@offset => @value}
101
+ @opt = {}
102
+ @get_opt = {:count => RightSupport::DB::CassandraModel::DEFAULT_COUNT}
103
+
104
+ @instance = RightSupport::DB::CassandraModel.new(@key, @attrs)
105
+
106
+ @conn = flexmock(:connection)
107
+ flexmock(RightSupport::DB::CassandraModel).should_receive(:conn).and_return(@conn)
108
+ @conn.should_receive(:insert).with(@column_family, @key, @attrs,@opt).and_return(true)
109
+ @conn.should_receive(:remove).with(@column_family, @key).and_return(true)
110
+ @conn.should_receive(:get).with(@column_family, @key, @get_opt).and_return(@attrs).by_default
111
+ @conn.should_receive(:multi_get).with(@column_family, [1,2], @opt).and_return(Hash.new)
112
+ end
113
+
114
+ describe "instance methods" do
115
+ context :save do
116
+ it 'saves the row' do
117
+ @instance.save.should be_true
118
+ end
119
+ end
120
+
121
+ context :destroy do
122
+ it 'destroys the row' do
123
+ @instance.destroy.should be_true
124
+ end
125
+ end
126
+
127
+ context :reload do
128
+ it 'returns a new object for the row' do
129
+ @instance.reload.should be_a_kind_of(RightSupport::DB::CassandraModel)
130
+ @instance.reload!.should be_a_kind_of(RightSupport::DB::CassandraModel)
131
+ end
132
+ end
133
+ end
134
+
135
+ describe "class methods" do
136
+ # We want to remain backward-compatible for existing services so we expect this call to be made
137
+ # as such: RightSupport::DB::CassandraModel.keyspace = "SatelliteService" and CassandraModel
138
+ # will append the RACK_ENV to the end of it. Ex: "SatelliteService_development"
139
+ context :keyspace= do
140
+ let(:keyspace) { 'SatelliteService' }
141
+
142
+ it 'appends the environment to the keyspace provided' do
143
+ RightSupport::DB::CassandraModel.keyspace = keyspace
144
+ RightSupport::DB::CassandraModel.send(:class_variable_get, :@@default_keyspace).should == (keyspace + "_" + (ENV['RACK_ENV'] || 'development'))
145
+ end
146
+ end
147
+
148
+ # If a current keyspace is provided it takes precedence over the default keyspace. If none is
149
+ # provided, the default keyspace should be returned.
150
+ context :keyspace do
151
+ let(:keyspace) { 'SatelliteService_' + ENV['RACK_ENV'] }
152
+
153
+ it 'returns the default keyspace if no current keyspace is set' do
154
+ RightSupport::DB::CassandraModel.send(:class_variable_set, :@@current_keyspace, nil)
155
+ RightSupport::DB::CassandraModel.send(:class_variable_set, :@@default_keyspace, keyspace)
156
+ RightSupport::DB::CassandraModel.keyspace.should == keyspace
157
+ end
158
+
159
+ it 'returns the current keyspace if a current keyspace is set' do
160
+ RightSupport::DB::CassandraModel.send(:class_variable_set, :@@current_keyspace, keyspace)
161
+ RightSupport::DB::CassandraModel.send(:class_variable_set, :@@default_keyspace, nil)
162
+ RightSupport::DB::CassandraModel.keyspace.should == keyspace
163
+ end
164
+ end
165
+
166
+ # This method assumes that a valid keyspace is passed in. If the keyspace does not exist we do NOT
167
+ # want to create it. CassandraModel should use the keyspace provided for the duration of the code
168
+ # executed within the block. Any requests processed outside of the block should execute using the
169
+ # default keyspace.
170
+ context :with_keyspace do
171
+ let(:keyspace) { 'SatelliteService_1' }
172
+ let(:default_keyspace) { 'SatelliteService' }
173
+
174
+ before(:each) do
175
+ RightSupport::DB::CassandraModel.keyspace = default_keyspace
176
+ end
177
+
178
+ it 'sets the current keyspace to the keyspace provided for execution within the block' do
179
+ RightSupport::DB::CassandraModel.with_keyspace(keyspace) do
180
+ RightSupport::DB::CassandraModel.keyspace.should == keyspace + "_" + 'test'
181
+ end
182
+ end
183
+
184
+ it 'resets back to the default keyspace for execution outside of the block' do
185
+ RightSupport::DB::CassandraModel.with_keyspace(keyspace) {}
186
+ RightSupport::DB::CassandraModel.keyspace.should == default_keyspace + "_" + 'test'
187
+ end
188
+ context 'append_env parameter' do
189
+ it 'appends the environment by default' do
190
+ RightSupport::DB::CassandraModel.with_keyspace('Monkey') do
191
+ RightSupport::DB::CassandraModel.keyspace.should == 'Monkey_test'
192
+ end
193
+ end
194
+
195
+ it 'appends the environment when append_env == true' do
196
+ RightSupport::DB::CassandraModel.with_keyspace('Monkey', true) do
197
+ RightSupport::DB::CassandraModel.keyspace.should == 'Monkey_test'
198
+ end
199
+ end
200
+
201
+ it 'does NOT append the environment when append_env == false' do
202
+ RightSupport::DB::CassandraModel.with_keyspace('Monkey_notatest', false) do
203
+ RightSupport::DB::CassandraModel.keyspace.should == 'Monkey_notatest'
204
+ end
205
+ end
206
+
207
+ it 'avoids double-appending the environment' do
208
+ RightSupport::DB::CassandraModel.with_keyspace('Monkey_test') do
209
+ RightSupport::DB::CassandraModel.keyspace.should == 'Monkey_test'
210
+ end
211
+ end
212
+ end
213
+ end
214
+
215
+ context :insert do
216
+ it 'inserts a row by using the class method' do
217
+ RightSupport::DB::CassandraModel.insert(@key, @attrs, @opt).should be_true
218
+ end
219
+ end
220
+
221
+ context :remove do
222
+ it 'removes a row by using the class method' do
223
+ RightSupport::DB::CassandraModel.remove(@key).should be_true
224
+ end
225
+ end
226
+
227
+ context :all do
228
+ it 'returns all existing rows for the specified array of keys' do
229
+ RightSupport::DB::CassandraModel.all([1, 2]).should be_a_kind_of(Hash)
230
+ end
231
+ end
232
+
233
+ context :get do
234
+ it 'returns row for the specified key' do
235
+ RightSupport::DB::CassandraModel.get(@key).should be_a_kind_of(RightSupport::DB::CassandraModel)
236
+ end
237
+
238
+ it 'returns only number of columns requested' do
239
+ attrs = {@offset + '1' => @value, @offset + '2' => @value}
240
+ get_opt = {:count => 2}
241
+ @conn.should_receive(:get).with(@column_family, @key, get_opt).and_return(attrs).once
242
+ RightSupport::DB::CassandraModel.get(@key, get_opt).attributes.should == attrs
243
+ end
244
+
245
+ it 'returns all columns for the specified key if no count specified' do
246
+ pending "Unpredictable behavior on ruby < 1.9" unless RUBY_VERSION >= "1.9"
247
+ default_count = RightSupport::DB::CassandraModel::DEFAULT_COUNT
248
+
249
+ RightSupport::DB::CassandraModel.instance_eval { remove_const :DEFAULT_COUNT }
250
+ RightSupport::DB::CassandraModel.const_set(:DEFAULT_COUNT, 2)
251
+ begin
252
+
253
+ attrs1 = {@offset + '1' => @value, @offset + '2' => @value}
254
+ attrs2 = {@offset + '3' => @value}
255
+ attrs = attrs1.merge(attrs2)
256
+ get_opt1 = {:count => 2}
257
+ get_opt2 = {:count => 2, :start => @offset + '2'}
258
+ @conn.should_receive(:get).with(@column_family, @key, get_opt1).and_return(attrs1).once
259
+ @conn.should_receive(:get).with(@column_family, @key, get_opt2).and_return(attrs2).once
260
+ RightSupport::DB::CassandraModel.get(@key).attributes.should == attrs
261
+ ensure
262
+ RightSupport::DB::CassandraModel.instance_eval { remove_const :DEFAULT_COUNT }
263
+ RightSupport::DB::CassandraModel.const_set(:DEFAULT_COUNT, default_count)
264
+ end
265
+ end
266
+
267
+ it 'returns nil if key not found' do
268
+ @conn.should_receive(:get).with(@column_family, @key, @get_opt).and_return({})
269
+ RightSupport::DB::CassandraModel.get(@key).should be_nil
270
+ end
271
+ end
272
+
273
+ def real_get_indexed(index, key, columns = nil, opt = {})
274
+ rows = {}
275
+ start = ""
276
+ count = DEFAULT_COUNT
277
+ expr = do_op(:create_idx_expr, index, key, "EQ")
278
+ opt = opt[:consistency] ? {:consistency => opt[:consistency]} : {}
279
+ while true
280
+ clause = do_op(:create_idx_clause, [expr], start, count)
281
+ chunk = do_op(:get_indexed_slices, column_family, clause, columns, opt)
282
+ rows.merge!(chunk)
283
+ if chunk.size == count
284
+ # Assume there are more chunks, use last key as start of next get
285
+ start = chunk.keys.last
286
+ else
287
+ # This must be the last chunk
288
+ break
289
+ end
290
+ end
291
+ rows
292
+ end
293
+
294
+ context :get_indexed do
295
+
296
+ before(:each) do
297
+ @column = flexmock(:column, :name => 'foo', :value => 'bar')
298
+ @column_or_super = flexmock(:column_or_super, :column => @column)
299
+ @rows = {@key => [@column_or_super]}
300
+ @index = 'index'
301
+ @index_key = 'index_key'
302
+ @start = ""
303
+ @count = RightSupport::DB::CassandraModel::DEFAULT_COUNT
304
+ @expr = flexmock(:expr)
305
+ @conn.should_receive(:create_idx_expr).and_return(@expr)
306
+ @clause = flexmock(:clause)
307
+ @conn.should_receive(:create_idx_clause).with([@expr], @start, @count).and_return(@clause).by_default
308
+ @conn.should_receive(:get_indexed_slices).with(@column_family, @clause, nil, {}).and_return(@rows).by_default
309
+ end
310
+
311
+ it 'returns row for the specified key' do
312
+ rows = RightSupport::DB::CassandraModel.get_indexed(@index, @index_key)
313
+ rows.should be_a_kind_of(Array)
314
+ rows.size.should == 1
315
+ rows.first.should be_a_kind_of(RightSupport::DB::CassandraModel)
316
+ end
317
+
318
+ it 'returns all rows for the specified key if no count specified' do
319
+ pending "Unpredictable behavior on ruby < 1.9" unless RUBY_VERSION >= "1.9"
320
+
321
+ default_count = RightSupport::DB::CassandraModel::DEFAULT_COUNT
322
+
323
+ RightSupport::DB::CassandraModel.instance_eval { remove_const :DEFAULT_COUNT }
324
+ RightSupport::DB::CassandraModel.const_set(:DEFAULT_COUNT, 2)
325
+ begin
326
+ key1 = @key + '8'
327
+ key2 = @key + '12'
328
+ key3 = @key + '13'
329
+ cols = {'foo' => 'bar'}
330
+ rows1 = {key1 => [@column_or_super], key2 => [@column_or_super]}
331
+ rows2 = {key3 => [@column_or_super]}
332
+ @conn.should_receive(:create_idx_clause).with([@expr], @start, 2).and_return(@clause).once
333
+ @conn.should_receive(:get_indexed_slices).with(@column_family, @clause, nil, {}).and_return(rows1).once
334
+ @conn.should_receive(:create_idx_clause).with([@expr], key2, 2).and_return(@clause).once
335
+ @conn.should_receive(:get_indexed_slices).with(@column_family, @clause, nil, {}).and_return(rows2).once
336
+ rows = RightSupport::DB::CassandraModel.get_indexed(@index, @index_key)
337
+ rows.size.should == 3
338
+ rows.inject({}) { |s, r| s[r.key] = r.attributes; s }.should == {key1 => cols, key2 => cols, key3 => cols}
339
+ ensure
340
+ RightSupport::DB::CassandraModel.instance_eval { remove_const :DEFAULT_COUNT }
341
+ RightSupport::DB::CassandraModel.const_set(:DEFAULT_COUNT, default_count)
342
+ end
343
+ end
344
+
345
+ it 'returns empty array if no rows found for key' do
346
+ @conn.should_receive(:get_indexed_slices).with(@column_family, @clause, nil, {}).and_return({}).once
347
+ RightSupport::DB::CassandraModel.get_indexed(@index, @index_key).should == []
348
+ end
349
+ end
350
+ end
351
+ end
352
+
353
+ context '.calculate_random_partitioner_token' do
354
+ it 'works' do
355
+ expected = 73001115008341200964825964898370608784
356
+ described_class.calculate_random_partitioner_token('71:foomonkeys').should == expected
357
+ end
358
+ end
359
+ end
@@ -0,0 +1,30 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ Proc-Type: 4,ENCRYPTED
3
+ DEK-Info: DES-EDE3-CBC,61C0BBB816A708D4
4
+
5
+ SQ/Y+U7z51OL/hx4YnfVPl6uqsOjpSjU2w4NFqB6EyBtMFgOoqW6ryuIi6ycHgWJ
6
+ YabUlMPdnexU+1BGqu9P2M9kQejfVddBFmbE09s54dwamk7q6RjaARN0UvHq6Ms9
7
+ r5/nqRBrinWtOeU/+7cV5qGp2/HbWC2bHAUCCwBcq+ymEpLOw/dpHpxjuiB5ZOLt
8
+ QzcEJ8ePlNDYvPxw4Wjvb5IDjS4MSoJfA5Y2ZXwVSI1d7mhx4Cekx3CkTMWKYIU8
9
+ FS6hO39tfPTcxb4os3FYl8D8TlRHv5atrsptKqYE4DKhZhoDA5yFbFJHZlEp+G6H
10
+ t+snMyuzEWNWq3wGI/gaglatUMq6airA50qticbw8kvz+67pPh2gkAgMXBHEGgPW
11
+ m0xnqaWf+MyQCUfaxjvxAq68Ced+H9ULLYFrzWAIuSh1M+QartuvP1ZOIcDpY83i
12
+ RybTJC5MLgGE0COM7oOtPfXO/rvdf6jqTr54HhYwq18aWrqjnacZi0JzNEFRtpNa
13
+ 5FNbwbQGT4Y8J1rOgbyjrd712oRhfjMAU39w4b6gEIATB4zDnMVkdb/Rde/nB7i4
14
+ CqDB9iSEbtQN4Ev5fXpIDrmhbdT/CURpzRvIt68x08qvX8KQwqDbLz39luocApxN
15
+ lnTihGiYAiNflMpDvhNL8MSLxYgL5Or2KVF/Ppc+1Qw23BEYDlaRRzc71PWdrVr8
16
+ UxEdFtqQnnthO7PabrwmLiPeArIGL4U8wrbXA3GbkbDtClftWMaC9JrzVJvXp1z7
17
+ sXZPhdZzSCg3n3ZbAGKYUx/G8AHojLKfAF3BHufnU9qM+6TS/KtTnhrvHSgYPcBn
18
+ etI7DWZ/mUnLwnsWfiQ3n5PeeUq/nU+IFJT+Y3r+TfFVCiGPW60XpfLzH1U4otKq
19
+ KaEnCQX6S7p1Jinx+FHL9fg1I50E6QUNO+N8XO4ay3Jzumz2yjZeudyt+uy954Hq
20
+ RfmDGYImqrkYrzd8d6hNUTBGnUfUTvq2k/orKhvcxtX+tr9WhNshnJcK18SgBRKT
21
+ 6XLybyioikVSpUGsL95kIhrspryO8v7/M1igWWrLu9fe/jUJLCFzlbGSRYDn+QTp
22
+ z7qpbBvxHPgu1fKurZ96nCcigVxQgY5rPwpQvG+mkD6YOhgDvSAjTos7Fagz6nb6
23
+ 01MufCVvFx+BBZEsol0Ag23RhXeJXvxkcF//hcPseCA/oB9Aqzyu+ml9mgp4v6P+
24
+ AgVopgGCfZR31CQ2b9AxdSARFCj2AFE9AdeNy268KSx8wLWAlzUcnGi57eK8WJM3
25
+ KTDOwJZDgZkjYyMZATpxOj8w3euAflQjQmyXpN1/Q0BW66Mj9+XzVk2yEpF2S0iE
26
+ xKzPcNEzlGMo1xo6mqVE/kIuRSodXuGp5Eoo8ITvpYWcSdtCTSKJNxAUqry/k9bg
27
+ 9sf3jSmSHzUd92pdM02p8A42HcaPGLmbuFjIfZPK7KoYmIdhJqy7s08CFUlk9XI/
28
+ PxdYph5J4WkAbeomPGUTFxEWV1cM2lvW4hotrx8MS50WLVZxxY1p7D+JxN3KeJyc
29
+ mytYpg2dxr8UF64NFKuyEmunkDTdYH2Oi7B7mAcw/QlBN+qCARP+tA==
30
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,12 @@
1
+ -----BEGIN DSA PRIVATE KEY-----
2
+ MIIBvAIBAAKBgQC1RlSYmT8VVtunF3xcpSdJfihaHAGzLH0nf2ooHcKIH6PyxjCe
3
+ Q93rFB69uyGPUJVawz3w0Y1B7B6h5eXI4SEKA4iqmSHXdFonO7wvOT5DTkzQl3yX
4
+ B1s4xU8+GW1MtUNKxHPzFpX40797Z1enO/EZRNLYt0P4IG86s/O+BqD6IwIVAJ24
5
+ m8A6ZFqsunyy2L5o9UInE+gfAoGAPuEeCrIginLFwSdwyrxEwC/gblKvOf/9+iMB
6
+ Jo+5fN2E9AHKrCsCa53E2lnUbXOdSKDR6yVmUQSB3EsBDoLqDOVJh/BWVTABebIO
7
+ WwnjQZX9UBGnsJwD4zpvtXLU4qnyFywSr1kdLDHMsGS3WVocJ9jOEH7Rh0xMM423
8
+ yYS4bUQCgYEApxLO5sTQS/Ej8+BFJQrMS3xHpONQxiMnTLE3q6qZXJRgHDgsqqwZ
9
+ pAfZCjRxvvfUfBGzjKwJlGQOLZVaGZOArGQF7NRtOfCHZtMBg1vubewXs64gmH5G
10
+ aXvJ17D6W2vCO04R/vXh43qKLDcPu7wGng+eWNaw/LkbdfC4k8uVfp4CFQCHe0yn
11
+ rgxFphSFqf8Spchmsg/coA==
12
+ -----END DSA PRIVATE KEY-----
@@ -0,0 +1,15 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICWwIBAAKBgQDm4VY+mDoYUsH+7idaNXP6Bq+YIXwqGNar6zgbPEe6qgpF9nSQ
3
+ B98gMObcZ9H7qGm3e/bQTCrlBAB/jMUQQbTyPsEy3pIKeWoPl7GTQpcSS9WZoHYX
4
+ yf4TN8MMOeJ3rGbyGb8Xm13R+SBpOMOZfnT3KUJLznIYVtBvv+uFz/C9ewIDAQAB
5
+ AoGAMJzLkvxsZwitziaI5KaSl9dmi4qpYRe/w40QUDO+CqCY7yg4XMc7hMSnJ0s4
6
+ 3FsWf0q7qhoPgg74p+KU75pWJbEHoYor6LqDuxov4DSx/2SfqmDBIAb9IQ4KWDr2
7
+ WU/o2/ivbHJ89FxCCroMzNg+qm8pAHVYQ72E/w/1sSRuQPECQQD4fes0OrE8qlJ0
8
+ 0UCxiTbotreNY7N/pKPIFqL/+ODcXJIHCyvVAMXw469r9KacrC/t8qKNatWk3mP1
9
+ uZzfoAJJAkEA7dsxOJcTqMAncOzbP2cXPkGvzyS06mUoziuZWDc+NAOy4R/V/xHW
10
+ +CUleXs06G9c/LoZ+E80MP600YvPtKUBowJAZXXMfnPkgDevGUGDX7n98IECazml
11
+ Rd3sfbs4bLmq3m7xtOyLxhnduGDO9I5dJSVtIIPseT+A4iNnvyI9elVz+QJALTBe
12
+ mpTBTGctVxv4z4Pje5V5NE6R/JI5fWn1GThtne4x9ulYe7xE7iIIi5rnw10c+nrU
13
+ 4kMR9Fj/u2vnizdqJwJACb7DY5rKZa/xgzgLtE5jW60zZWvwS9LYUs+1ND6CeiFy
14
+ s3EiH2z+zbSO+cnMtCutdRKIHk3wy6tyRKOq0EMafA==
15
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1 @@
1
+ ssh-dss AAAAB3NzaC1kc3MAAACBALVGVJiZPxVW26cXfFylJ0l+KFocAbMsfSd/aigdwogfo/LGMJ5D3esUHr27IY9QlVrDPfDRjUHsHqHl5cjhIQoDiKqZIdd0Wic7vC85PkNOTNCXfJcHWzjFTz4ZbUy1Q0rEc/MWlfjTv3tnV6c78RlE0ti3Q/ggbzqz874GoPojAAAAFQCduJvAOmRarLp8sti+aPVCJxPoHwAAAIA+4R4KsiCKcsXBJ3DKvETAL+BuUq85//36IwEmj7l83YT0AcqsKwJrncTaWdRtc51IoNHrJWZRBIHcSwEOguoM5UmH8FZVMAF5sg5bCeNBlf1QEaewnAPjOm+1ctTiqfIXLBKvWR0sMcywZLdZWhwn2M4QftGHTEwzjbfJhLhtRAAAAIEApxLO5sTQS/Ej8+BFJQrMS3xHpONQxiMnTLE3q6qZXJRgHDgsqqwZpAfZCjRxvvfUfBGzjKwJlGQOLZVaGZOArGQF7NRtOfCHZtMBg1vubewXs64gmH5GaXvJ17D6W2vCO04R/vXh43qKLDcPu7wGng+eWNaw/LkbdfC4k8uVfp4= user@host
@@ -0,0 +1,5 @@
1
+ -----BEGIN RSA PUBLIC KEY-----
2
+ MIGJAoGBAObhVj6YOhhSwf7uJ1o1c/oGr5ghfCoY1qvrOBs8R7qqCkX2dJAH3yAw
3
+ 5txn0fuoabd79tBMKuUEAH+MxRBBtPI+wTLekgp5ag+XsZNClxJL1ZmgdhfJ/hM3
4
+ www54nesZvIZvxebXdH5IGk4w5l+dPcpQkvOchhW0G+/64XP8L17AgMBAAE=
5
+ -----END RSA PUBLIC KEY-----
@@ -0,0 +1 @@
1
+ ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEApfGJ2lzcKgWq50u4yhZyP7yDjA4CF2pV19TUOlXg4a40FCuKi7JIqPCyixmrWYrvRFz+5zY+gHWOHkCfjNaDryUgPsBMzk2DZDD8fsrJ5KU7QDAa1RMbixnWsWTDcXGhHxC7jtRV7qKFvribLYEoUfVbWZYQR3Wl9kfc78sF6Z2TZuL2Fb9YJc5f2uDz6+I6oy8LtGci4Y2hKVYxrN5tgvFcwkE8JsRaAnjWicfoHRUIBZ/tdT76EMhBEKdO63hO9AZ8phTyZoJyLzykDRaelBUYXjG0LQXTq4jiJhKa07kv0XIgNwnz4zB9qtiOHXm6KZZDxy7xnVXOFum+JqcUxQ== user@host
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe RightSupport::Log::ExceptionLogger do
4
+ before(:all) do
5
+ @actual_logger = Logger.new(StringIO.new)
6
+ @logger = RightSupport::Log::ExceptionLogger.new(@actual_logger)
7
+ @exception = Exception.new('message')
8
+ end
9
+
10
+ context :exception do
11
+ it 'logs an error with exception information' do
12
+ flexmock(@actual_logger).should_receive(:fatal)
13
+ @logger.exception('desc', @exception)
14
+ end
15
+ end
16
+
17
+ context 'class methods' do
18
+ context :format_exception do
19
+ it 'includes the description' do
20
+ RightSupport::Log::ExceptionLogger.format_exception('desc').should == 'desc'
21
+ end
22
+
23
+ it 'includes the exception message if present' do
24
+ e = ArgumentError.new("err")
25
+ RightSupport::Log::ExceptionLogger.format_exception('desc', e).should =~ /desc \(ArgumentError: err.*/
26
+ end
27
+
28
+ it 'includes the exception string if present' do
29
+ RightSupport::Log::ExceptionLogger.format_exception('desc', 'err', :no_trace).should == 'desc (err)'
30
+ end
31
+
32
+ context 'with backtrace=:no_trace' do
33
+ it 'does not include a backtrace' do
34
+ e = ArgumentError.new("err")
35
+ RightSupport::Log::ExceptionLogger.format_exception('desc', e, :no_trace).should == 'desc (ArgumentError: err)'
36
+ end
37
+ end
38
+
39
+ context 'with backtrace=:caller' do
40
+ it 'includes a single line of backtrace' do
41
+ begin
42
+ raise ArgumentError.new("err")
43
+ rescue Exception => e
44
+ RightSupport::Log::ExceptionLogger.format_exception('desc', e, :caller).should == "desc (ArgumentError: err IN #{e.backtrace[0]})"
45
+ end
46
+ end
47
+
48
+ it 'defaults to :caller trace' do
49
+ begin
50
+ raise ArgumentError.new("err")
51
+ rescue Exception => e
52
+ RightSupport::Log::ExceptionLogger.format_exception('desc', e).should == "desc (ArgumentError: err IN #{e.backtrace[0]})"
53
+ end
54
+ end
55
+
56
+ it 'excludes backtrace if the exception does not respond to backtrace' do
57
+ RightSupport::Log::ExceptionLogger.format_exception('desc', 'err').should == "desc (err)"
58
+ end
59
+ end
60
+
61
+ context 'with backtrace=:trace' do
62
+ it 'includes a full backtrace' do
63
+ begin
64
+ raise ArgumentError.new("err")
65
+ rescue Exception => e
66
+ RightSupport::Log::ExceptionLogger.format_exception('desc', e, :trace).should == "desc (ArgumentError: err IN\n " + e.backtrace.join("\n ") + ")"
67
+ end
68
+ end
69
+
70
+ it 'excludes backtrace if the exception does not respond to backtrace' do
71
+ RightSupport::Log::ExceptionLogger.format_exception('desc', 'err').should == "desc (err)"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe RightSupport::Log::FilterLogger do
4
+ it 'does method_missing correctly'
5
+ it 'does respond_to? correctly'
6
+ it 'transparently proxies Logger methods to underlying object'
7
+ it 'filters log messages'
8
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ class InnocentVictim
4
+ include RightSupport::Log::Mixin
5
+ end
6
+
7
+ describe RightSupport::Log::Mixin do
8
+ context 'when mixed into a base class' do
9
+ before(:each) do
10
+ @victim = InnocentVictim.new
11
+ end
12
+
13
+ it 'provides a class-level accessor' do
14
+ @victim.class.should respond_to(:logger)
15
+ @victim.class.should respond_to(:logger=)
16
+ end
17
+
18
+ it 'provides an instance-level accessor' do
19
+ @victim.should respond_to(:logger)
20
+ end
21
+
22
+ context :logger do
23
+ context 'without a logger' do
24
+ before(:each) do
25
+ @victim.class.logger = nil
26
+ end
27
+
28
+ it 'uses the default logger' do
29
+ flexmock(RightSupport::Log::Mixin.default_logger).should_receive(:info).twice.and_return(true)
30
+ @victim.class.logger.info('lalalala').should be_true
31
+ @victim.logger.info('lalalala').should be_true
32
+ end
33
+ end
34
+
35
+ context 'with class logger' do
36
+ before(:each) do
37
+ @logger = mock_logger
38
+ @victim.class.logger = @logger
39
+ end
40
+
41
+ it 'uses class logger' do
42
+ @logger.should_receive(:info).and_return(true).twice
43
+ @victim.class.logger.info('lalalala').should be_true
44
+ @victim.logger.info('lalalala').should be_true
45
+ end
46
+
47
+ context 'with instance logger' do
48
+ before(:each) do
49
+ @instance_logger = mock_logger
50
+ @victim.logger = @instance_logger
51
+ end
52
+
53
+ it 'uses instance logger' do
54
+ @instance_logger.should_receive(:info).and_return(true).once
55
+ @logger.should_receive(:info).never
56
+ @victim.logger.info('lalalala').should be_true
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,54 @@
1
+ #
2
+ # Copyright (c) 2009-2012 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require 'spec_helper'
24
+
25
+ describe RightSupport::Log::Multiplexer do
26
+
27
+ before(:all) do
28
+ @target1 = RightSupport::Log::NullLogger.new
29
+ @target2 = RightSupport::Log::NullLogger.new
30
+ @target3 = RightSupport::Log::NullLogger.new
31
+ @multiplexer = RightSupport::Log::Multiplexer.new(@target1, @target2, @target3)
32
+ end
33
+
34
+ it 'multiplexes method calls to all callers' do
35
+ flexmock(@target1).should_receive(:some_method).with('arg', 'arg2').once
36
+ flexmock(@target2).should_receive(:some_method).with('arg', 'arg2').once
37
+ flexmock(@target3).should_receive(:some_method).with('arg', 'arg2').once
38
+ @multiplexer.some_method('arg', 'arg2')
39
+ end
40
+
41
+ it 'returns the result returned by the first target' do
42
+ flexmock(@target1).should_receive(:some_method).with('arg', 'arg2').and_return('res1').once
43
+ flexmock(@target2).should_receive(:some_method).with('arg', 'arg2').and_return('res2').once
44
+ flexmock(@target3).should_receive(:some_method).with('arg', 'arg2').and_return('res3').once
45
+ @multiplexer.some_method('arg', 'arg2').should == 'res1'
46
+ end
47
+
48
+ it 'multiplexes #warn by undefining Object#warn' do
49
+ flexmock(@target1).should_receive(:warn).with('arg').and_return('res1')
50
+ flexmock(@target2).should_receive(:warn).with('arg').and_return('res2')
51
+ flexmock(@target3).should_receive(:warn).with('arg').and_return('res3')
52
+ @multiplexer.warn('arg').should == 'res1'
53
+ end
54
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe RightSupport::Log::NullLogger do
4
+ before(:each) do
5
+ @logger = RightSupport::Log::NullLogger.new
6
+ end
7
+
8
+ context 'log levels' do
9
+ [:debug, :info, :warn, :error, :fatal].each do |method|
10
+ it "responds to ##{method}" do
11
+ block_called = false
12
+ @logger.__send__(method, 'lalalala').should be_true
13
+ @logger.__send__(method) { block_called = true ; 'lalalala' }.should be_true
14
+ block_called.should be_true
15
+ end
16
+ end
17
+ end
18
+
19
+ context '<< method' do
20
+ it 'responds like Logger' do
21
+ (@logger << 'lalalala').should == 8
22
+ end
23
+ end
24
+
25
+ context :close do
26
+ it 'responds' do
27
+ @logger.close.should be_nil
28
+ end
29
+
30
+ it 'is idempotent' do
31
+ @logger.close.should be_nil
32
+ @logger.close.should be_nil
33
+ @logger.close.should be_nil
34
+ end
35
+ end
36
+ end