right_agent 2.6.3 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 16d90487a104c3df9bda429bb53e65aea08986c3
4
- data.tar.gz: 01b33304e25eb7399946c2a08db53a493dcfeb22
3
+ metadata.gz: 74c2e07823dff52a0a487855918d9fe020f4509b
4
+ data.tar.gz: b9fc140fd85dc787e63a04880e3b195024ca0f42
5
5
  SHA512:
6
- metadata.gz: 740c5fc4895b8b39b36196908548b22f614af3bd1b69bcdd1784703c9363816b513e07c88c9ba01ce2c89c6ee2bf3041a9b02e262fc0e44baaa8a6a05bc8d570
7
- data.tar.gz: cf41ede79b081d7db299440e0e4753751088bb093c2ce85b7dc3f615e510aba2d5c501ee082687b6a18ae1915825ec611b08cf832bd2ef4db19197a78cc1c135
6
+ metadata.gz: a17751f1a016b2e81cdebb0281449c90db0be2cf4e8c17062d54ce36ee29d1517c4d2c1686debf81f75c34f4ae054d109ff9b3f45453b9db27070affb3df7f9b
7
+ data.tar.gz: f5720ae5a981c8b54a6d3d811fc8f35e8c0ea8c02d573c29fc78e9011c28fbf33aa7d9d089c0337f2a653f250f120cc94fa0403337a23b98681f6728f3037a70
data/Rakefile CHANGED
@@ -48,7 +48,6 @@ task :default => :spec
48
48
 
49
49
  desc 'Run unit tests'
50
50
  RSpec::Core::RakeTask.new do |t|
51
- t.rspec_opts = RSPEC_OPTS
52
51
  t.pattern = Dir['**/*_spec.rb']
53
52
  end
54
53
 
@@ -273,40 +273,57 @@ module RightScale
273
273
  end
274
274
  end
275
275
 
276
- # Reconnect with server by periodically checking health
277
- # Randomize when initially start checking to reduce server spiking
276
+ # If EventMachine reactor is running, begin attempting to periodically
277
+ # reconnect with server by checking health. Randomize initial attempt to
278
+ # reduce server spiking.
279
+ #
280
+ # If EventMachine reactor is NOT running, attempt to reconnect once
281
+ # and raise any exception that is encountered.
278
282
  #
279
283
  # @return [TrueClass] always true
280
284
  def reconnect
281
285
  unless @reconnecting
282
286
  @reconnecting = true
283
- @stats["reconnects"].update("initiate")
284
- @reconnect_timer = EM_S::PeriodicTimer.new(rand(@options[:reconnect_interval])) do
285
- begin
286
- create_http_client
287
- if check_health == :connected
288
- enable_use
289
- # Check state again since may have disconnected during enable_use
290
- if self.state == :connected
291
- @stats["reconnects"].update("success")
292
- @reconnect_timer.cancel if @reconnect_timer # only need 'if' for test purposes
293
- @reconnect_timer = @reconnecting = nil
294
- end
287
+
288
+ if EM.reactor_running?
289
+ @stats["reconnects"].update("initiate")
290
+ @reconnect_timer = EM_S::PeriodicTimer.new(rand(@options[:reconnect_interval])) do
291
+ begin
292
+ reconnect_once
293
+ rescue Exception => e
294
+ ErrorTracker.log(self, "Failed #{@options[:server_name]} reconnect", e, nil, :caller)
295
+ @stats["reconnects"].update("failure")
296
+ self.state = :disconnected
295
297
  end
296
- rescue Exception => e
297
- ErrorTracker.log(self, "Failed #{@options[:server_name]} reconnect", e, nil, :caller)
298
- @stats["reconnects"].update("failure")
299
- self.state = :disconnected
298
+ @reconnect_timer.interval = @options[:reconnect_interval] if @reconnect_timer
300
299
  end
301
- @reconnect_timer.interval = @options[:reconnect_interval] if @reconnect_timer
300
+ else
301
+ reconnect_once
302
302
  end
303
303
  end
304
+
304
305
  true
305
306
  end
306
307
 
307
- # Make request via HTTP
308
- # Rely on underlying HTTP client to log request and response
309
- # Retry request if response indicates to or if there are connectivity failures
308
+ # Attempt to reconnect exactly once. Perform no exception handling,
309
+ # state management, or scheduling of future reconnects, but cancel the
310
+ # reconnect timer if it exists and set @reconnecting, et al to nil.
311
+ def reconnect_once
312
+ create_http_client
313
+ if check_health == :connected
314
+ enable_use
315
+ # Check state again since may have disconnected during enable_use
316
+ if self.state == :connected
317
+ @stats["reconnects"].update("success")
318
+ @reconnect_timer.cancel if @reconnect_timer
319
+ @reconnect_timer = @reconnecting = nil
320
+ end
321
+ end
322
+ end
323
+
324
+ # Make request via HTTP. Attempt to reconnect first if disconnected and EM reactor is not running.
325
+ # Rely on underlying HTTP client to log request and response.
326
+ # Retry request if response indicates to or if there are connectivity failures.
310
327
  #
311
328
  # There are also several timeouts involved:
312
329
  # - Underlying BalancedHttpClient connection open timeout (:open_timeout)
@@ -364,6 +381,7 @@ module RightScale
364
381
  :request_timeout => @options[:request_timeout],
365
382
  :request_uuid => request_uuid,
366
383
  :headers => headers }
384
+ reconnect_once if (:disconnected == state) && !EM.reactor_running?
367
385
  raise Exceptions::ConnectivityFailure, "#{@type} client not connected" unless [:connected, :closing].include?(state)
368
386
  result = @http_client.send(verb, path, params, http_options.merge(options))
369
387
  rescue StandardError => e
@@ -40,7 +40,7 @@ module RightScale
40
40
  @public_key = args[2]
41
41
  @common_name = args[3] || ''
42
42
  @superuser = args[4] || false
43
- @expires_at = Time.at(args[5]) if args[5] && (args[5] != 0) # nil -> 0 because of expires_at.to_i below
43
+ @expires_at = Time.at(args[5].to_i) if args[5] && (args[5] != 0) # nil -> 0 because of expires_at.to_i below
44
44
  @public_keys = args[6]
45
45
  @profile_data = args[7]
46
46
  @public_key_fingerprints = args[8]
@@ -14,7 +14,7 @@ module RightScale
14
14
  # Tracker for unexpected errors
15
15
  # Logs them with appropriate trace information
16
16
  # Accumulates statistics about exceptions
17
- # Reports exceptions to external Errbit service via HydraulicBrake
17
+ # Reports exceptions to external Errbit service via Airbrake
18
18
  class ErrorTracker
19
19
 
20
20
  include RightSupport::Ruby::EasySingleton
@@ -104,36 +104,38 @@ module RightScale
104
104
  # @return [TrueClass] always true
105
105
  def notify(exception, packet = nil, agent = nil, component = nil)
106
106
  if @notify_enabled
107
- data = {
108
- :error_message => exception.respond_to?(:message) ? exception.message : exception.to_s,
109
- :backtrace => exception.respond_to?(:backtrace) ? exception.backtrace : caller,
110
- :environment_name => ENV["RAILS_ENV"],
111
- }
112
- if agent
113
- data[:cgi_data] = (@cgi_data || {}).merge(:agent_class => agent.class.name)
114
- elsif @cgi_data
115
- data[:cgi_data] = @cgi_data
116
- end
117
- data[:error_class] = exception.class.name if exception.is_a?(Exception)
118
- data[:component] = component if component
119
107
  if packet && packet.is_a?(Packet)
120
- data[:action] = packet.type.split("/").last if packet.respond_to?(:type)
108
+ action = packet.type.split("/").last if packet.respond_to?(:type)
121
109
  params = packet.respond_to?(:payload) && packet.payload
122
110
  uuid = packet.respond_to?(:token) && packet.token
123
111
  elsif packet.is_a?(Hash)
124
- action = packet[:path] || packet["path"]
125
- data[:action] = action.split("/").last if action
112
+ action_path = packet[:path] || packet["path"]
113
+ action = action_path.split("/").last if action_path
126
114
  params = packet[:data] || packet["data"]
127
115
  uuid = packet[:uuid] || packet["uuid"]
128
116
  else
129
117
  params = uuid = nil
130
118
  end
131
- data[:parameters] = params.is_a?(Hash) ? filter(params) : {:param => params} if params
132
- data[:session_data] = {:uuid => uuid} if uuid
133
- HydraulicBrake.notify(data)
119
+
120
+ n = Airbrake.build_notice(
121
+ exception,
122
+ { component: component, action: action },
123
+ :right_agent )
124
+
125
+ n[:params] = params.is_a?(Hash) ? filter(params) : {:param => params} if params
126
+ n[:session] = { :uuid => uuid } if uuid
127
+
128
+ if agent
129
+ n[:environment] = (@cgi_data || {}).merge(:agent_class => agent.class.name)
130
+ elsif @cgi_data
131
+ n[:environment] = @cgi_data || {}
132
+ end
133
+
134
+ Airbrake.notify(n, {}, :right_agent)
134
135
  end
135
136
  true
136
137
  rescue Exception => e
138
+ raise if e.class.name =~ /^RSpec/ # keep us from going insane while running tests
137
139
  Log.error("Failed to notify Errbit", e, :trace)
138
140
  end
139
141
 
@@ -168,7 +170,7 @@ module RightScale
168
170
  @exception_stats.reset
169
171
  end
170
172
 
171
- # Configure HydraulicBreak for exception notification
173
+ # Configure Airbrake for exception notification
172
174
  #
173
175
  # @param [String] agent_name uniquely identifying agent process on given server
174
176
  #
@@ -181,11 +183,11 @@ module RightScale
181
183
  #
182
184
  # @return [TrueClass] always true
183
185
  #
184
- # @raise [RuntimeError] hydraulic_brake gem missing
186
+ # @raise [RuntimeError] airbrake gem missing
185
187
  def notify_init(agent_name, options)
186
188
  if options[:airbrake_endpoint] && options[:airbrake_api_key]
187
- unless require_succeeds?("hydraulic_brake")
188
- raise RuntimeError, "hydraulic_brake gem missing - required if airbrake options used in ErrorTracker"
189
+ unless require_succeeds?("airbrake-ruby")
190
+ raise RuntimeError, "airbrake-ruby gem missing - required if airbrake options used in ErrorTracker"
189
191
  end
190
192
 
191
193
  @cgi_data = {
@@ -194,21 +196,23 @@ module RightScale
194
196
  :agent_name => agent_name
195
197
  }
196
198
  @cgi_data[:shard_id] = options[:shard_id] if options[:shard_id]
197
- @cgi_data[:sha] = CURRENT_SOURCE_SHA if defined?(CURRENT_SOURCE_SHA)
198
-
199
- uri = URI.parse(options[:airbrake_endpoint])
200
- HydraulicBrake.configure do |config|
201
- config.secure = (uri.scheme == "https")
202
- config.host = uri.host
203
- config.port = uri.port
204
- config.api_key = options[:airbrake_api_key]
205
- config.project_root = AgentConfig.root_dir
206
- end
207
199
  @filter_params = (options[:filter_params] || []).map { |p| p.to_s }
208
200
  @notify_enabled = true
201
+
202
+ return true if Airbrake.send(:configured?, :right_agent)
203
+
204
+ Airbrake.configure(:right_agent) do |config|
205
+ config.host = options[:airbrake_endpoint]
206
+ config.project_id = options[:airbrake_api_key]
207
+ config.project_key = options[:airbrake_api_key]
208
+ config.root_directory = AgentConfig.root_dir
209
+ config.environment = ENV['RAILS_ENV']
210
+ config.app_version = CURRENT_SOURCE_SHA if defined?(CURRENT_SOURCE_SHA)
211
+ end
209
212
  else
210
213
  @notify_enabled = false
211
214
  end
215
+
212
216
  true
213
217
  end
214
218
 
@@ -416,22 +416,21 @@ module RightScale
416
416
 
417
417
  # Initialize logger
418
418
  #
419
- # === Parameters
420
- # identity(String):: Log identity
421
- # path(String):: Log directory path
422
- # opts[:force](TrueClass|FalseClass):: Whether to re-initialize if logger
423
- # is already initialized
424
- # opts[:print](TrueClass|FalseClass):: Whether to print to STDOUT log destination
419
+ # @param [String] identity RightNet identity (for log file name or syslog program name)
420
+ # @param [String] path directory to create log files in
421
+ # @option opts [Boolean] :force whether to re-initialize if logger is already initialized
422
+ # @option opts [Boolean] :print whether to print log-location info to STDOUT
425
423
  #
426
- # === Return
427
- # logger(RightScale::Multiplexer):: logger instance
424
+ # @return [RightScale::Multiplexer] logger instance
428
425
  def init(identity=nil, path=nil, opts={})
429
426
  if opts[:force] || !@initialized
430
427
  @initialized = true
431
428
  @level_frozen = false
432
- logger = nil
429
+ logger = opts[:logger]
433
430
 
434
- if @log_to_file_only || Platform.windows?
431
+ if !logger.nil?
432
+ $stderr.puts "Logging to already-initialized #{logger.class.name}" if opts[:print]
433
+ elsif @log_to_file_only || Platform.windows?
435
434
  if path
436
435
  file = File.join(path, "#{identity}.log")
437
436
  else
@@ -25,8 +25,8 @@ require 'rbconfig'
25
25
 
26
26
  Gem::Specification.new do |spec|
27
27
  spec.name = 'right_agent'
28
- spec.version = '2.6.3'
29
- spec.date = '2015-09-16'
28
+ spec.version = '2.7.0'
29
+ spec.date = '2016-05-20'
30
30
  spec.authors = ['Lee Kirchhoff', 'Raphael Simon', 'Tony Spataro', 'Scott Messier']
31
31
  spec.email = 'lee@rightscale.com'
32
32
  spec.homepage = 'https://github.com/rightscale/right_agent'
@@ -44,7 +44,7 @@ Gem::Specification.new do |spec|
44
44
  spec.add_dependency('faye-websocket', '~> 0.7.0')
45
45
  spec.add_dependency('eventmachine', ['>= 0.12.10', '< 2.0'])
46
46
  spec.add_dependency('net-ssh', '~> 2.0')
47
- spec.add_dependency('addressable', '~> 2.3', '< 2.4')
47
+ spec.add_dependency('addressable', '~> 2.3')
48
48
 
49
49
  # TEAL HACK: rake gem may override current RUBY_PLATFORM to allow building
50
50
  # gems for all supported platforms from any platform. rubygems 1.8.x makes it
@@ -34,6 +34,7 @@ describe RightScale::BaseRetryClient do
34
34
  @log.should_receive(:warning).by_default.and_return { |m| raise RightScale::Log.format(*m) }
35
35
  @url = "http://test.com"
36
36
  @timer = flexmock("timer", :cancel => true, :interval= => 0).by_default
37
+ flexmock(EM).should_receive(:reactor_running?).and_return(true).by_default
37
38
  flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).by_default
38
39
  @http_client = flexmock("http client", :get => true, :check_health => true, :close => true).by_default
39
40
  flexmock(RightScale::BalancedHttpClient).should_receive(:new).and_return(@http_client).by_default
@@ -338,82 +339,102 @@ describe RightScale::BaseRetryClient do
338
339
  @client.instance_variable_set(:@reconnecting, nil)
339
340
  end
340
341
 
341
- it "waits random interval for initial reconnect attempt" do
342
- flexmock(@client).should_receive(:rand).with(15).and_return(10).once
343
- flexmock(EM::PeriodicTimer).should_receive(:new).with(10, Proc).and_return(@timer).once
344
- @client.send(:reconnect).should be_true
345
- end
346
-
347
- it "attempts to connect even if currently connected" do
348
- flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
349
- @client.send(:create_http_client)
350
- @client.send(:check_health).should == :connected
351
- flexmock(@client).should_receive(:check_health).once
352
- @client.send(:reconnect).should be_true
353
- end
354
-
355
- it "recreates HTTP client and checks health" do
356
- flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
357
- flexmock(RightScale::BalancedHttpClient).should_receive(:new).and_return(@http_client).once
358
- @http_client.should_receive(:check_health).once
359
- @client.send(:reconnect).should be_true
360
- end
361
-
362
- context "when health check successful" do
363
- it "enables use of client" do
364
- flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
365
- flexmock(@client).should_receive(:enable_use).once
342
+ context 'given EventMachine is running' do
343
+ it "waits random interval for initial reconnect attempt" do
344
+ flexmock(@client).should_receive(:rand).with(15).and_return(10).once
345
+ flexmock(EM::PeriodicTimer).should_receive(:new).with(10, Proc).and_return(@timer).once
366
346
  @client.send(:reconnect).should be_true
367
347
  end
368
348
 
369
- it "rechecks state after enables use" do
349
+ it "attempts to connect even if currently connected" do
370
350
  flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
371
- flexmock(@client).should_receive(:enable_use).and_return { @client.instance_variable_set(:@state, :disconnected) }.once
351
+ @client.send(:create_http_client)
352
+ @client.send(:check_health).should == :connected
353
+ flexmock(@client).should_receive(:check_health).once
372
354
  @client.send(:reconnect).should be_true
373
- @client.instance_variable_get(:@reconnecting).should be true
374
355
  end
375
356
 
376
- it "disables timer" do
377
- @client.send(:reconnect); @client.instance_variable_set(:@reconnecting, nil) # to get @reconnect_timer initialized
378
- @client.instance_variable_set(:@reconnecting, nil)
379
- @timer.should_receive(:cancel).once
357
+ it "recreates HTTP client and checks health" do
380
358
  flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
359
+ flexmock(RightScale::BalancedHttpClient).should_receive(:new).and_return(@http_client).once
360
+ @http_client.should_receive(:check_health).once
381
361
  @client.send(:reconnect).should be_true
382
- @client.instance_variable_get(:@reconnecting).should be_nil
383
362
  end
384
363
 
385
- it "does not reset timer interval" do
386
- @timer.should_receive(:interval=).never
387
- flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
364
+ context "when health check successful" do
365
+ it "enables use of client" do
366
+ flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
367
+ flexmock(@client).should_receive(:enable_use).once
368
+ @client.send(:reconnect).should be_true
369
+ end
370
+
371
+ it "rechecks state after enables use" do
372
+ flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
373
+ flexmock(@client).should_receive(:enable_use).and_return { @client.instance_variable_set(:@state, :disconnected) }.once
374
+ @client.send(:reconnect).should be_true
375
+ @client.instance_variable_get(:@reconnecting).should be true
376
+ end
377
+
378
+ it "disables timer" do
379
+ @client.send(:reconnect); @client.instance_variable_set(:@reconnecting, nil) # to get @reconnect_timer initialized
380
+ @client.instance_variable_set(:@reconnecting, nil)
381
+ @timer.should_receive(:cancel).once
382
+ flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
383
+ @client.send(:reconnect).should be_true
384
+ @client.instance_variable_get(:@reconnecting).should be_nil
385
+ end
386
+
387
+ it "does not reset timer interval" do
388
+ @timer.should_receive(:interval=).never
389
+ flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
390
+ @client.send(:reconnect).should be_true
391
+ end
392
+ end
393
+
394
+ context "when reconnect fails" do
395
+ it "logs error if exception is raised" do
396
+ flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
397
+ flexmock(@client).should_receive(:enable_use).and_raise(StandardError).once
398
+ @log.should_receive(:error).with("Failed test reconnect", StandardError, :caller).once
399
+ @client.send(:reconnect).should be_true
400
+ @client.state.should == :disconnected
401
+ end
402
+
403
+ it "resets the timer interval to the configured value" do
404
+ @client.send(:reconnect); @client.instance_variable_set(:@reconnecting, nil) # to get @reconnect_timer initialized
405
+ @log.should_receive(:error).with("Failed test health check", StandardError, :caller).once
406
+ @http_client.should_receive(:check_health).and_raise(StandardError).once
407
+ @timer.should_receive(:interval=).with(15).once
408
+ flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
409
+ @client.send(:reconnect).should be_true
410
+ end
411
+ end
412
+
413
+ it "does nothing if already reconnecting" do
414
+ flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).once
415
+ @client.send(:reconnect).should be_true
416
+ @client.instance_variable_get(:@reconnecting).should be_true
388
417
  @client.send(:reconnect).should be_true
418
+ @client.instance_variable_get(:@reconnecting).should be_true
389
419
  end
390
420
  end
391
421
 
392
- context "when reconnect fails" do
393
- it "logs error if exception is raised" do
394
- flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
395
- flexmock(@client).should_receive(:enable_use).and_raise(StandardError).once
396
- @log.should_receive(:error).with("Failed test reconnect", StandardError, :caller).once
397
- @client.send(:reconnect).should be_true
398
- @client.state.should == :disconnected
422
+ context 'given EventMachine is inactive' do
423
+ before(:each) do
424
+ flexmock(EM).should_receive(:reactor_running?).and_return(false)
399
425
  end
400
426
 
401
- it "resets the timer interval to the configured value" do
402
- @client.send(:reconnect); @client.instance_variable_set(:@reconnecting, nil) # to get @reconnect_timer initialized
403
- @log.should_receive(:error).with("Failed test health check", StandardError, :caller).once
404
- @http_client.should_receive(:check_health).and_raise(StandardError).once
405
- @timer.should_receive(:interval=).with(15).once
406
- flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).and_yield
427
+ it "tries once" do
407
428
  @client.send(:reconnect).should be_true
408
429
  end
409
- end
410
430
 
411
- it "does nothing if already reconnecting" do
412
- flexmock(EM::PeriodicTimer).should_receive(:new).and_return(@timer).once
413
- @client.send(:reconnect).should be_true
414
- @client.instance_variable_get(:@reconnecting).should be_true
415
- @client.send(:reconnect).should be_true
416
- @client.instance_variable_get(:@reconnecting).should be_true
431
+ it "raises exceptions" do
432
+ lambda do
433
+ flexmock(@client).should_receive(:create_http_client).and_raise(Exception)
434
+
435
+ @client.send(:reconnect)
436
+ end.should raise_error(Exception)
437
+ end
417
438
  end
418
439
  end
419
440
 
@@ -431,6 +452,26 @@ describe RightScale::BaseRetryClient do
431
452
  @client.init(:test, @auth_client, @options)
432
453
  end
433
454
 
455
+ context 'given EventMachine is inactive' do
456
+ before(:each) do
457
+ flexmock(EM).should_receive(:reactor_running?).and_return(false)
458
+ end
459
+
460
+ it 'reconnects if necessary' do
461
+ @client.instance_variable_set(:@state, :disconnected)
462
+ @http_client.should_receive(:get).with(@path, @params, Hash).once
463
+ @client.send(:make_request, :get, @path, @params)
464
+ end
465
+
466
+ it 'raises connection errors' do
467
+ @client.instance_variable_set(:@state, :disconnected)
468
+ @http_client.should_receive(:check_health).and_raise(Exception)
469
+ lambda {
470
+ @client.send(:make_request, :get, @path, @params)
471
+ }.should raise_error(Exception)
472
+ end
473
+ end
474
+
434
475
  it "raises exception if terminating" do
435
476
  @client.close
436
477
  lambda { @client.send(:make_request, :get, @path) }.should raise_error(RightScale::Exceptions::Terminating)
@@ -20,7 +20,7 @@
20
20
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
 
23
- require 'hydraulic_brake'
23
+ require 'airbrake-ruby'
24
24
 
25
25
  require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
26
26
 
@@ -39,7 +39,7 @@ describe RightScale::ErrorTracker do
39
39
  @trace_level = RightScale::Agent::TRACE_LEVEL
40
40
  @tracker = RightScale::ErrorTracker.instance
41
41
  @log = flexmock(RightScale::Log)
42
- @brake = flexmock(HydraulicBrake)
42
+ @brake = flexmock(Airbrake)
43
43
  @options = {
44
44
  :shard_id => @shard_id,
45
45
  :trace_level => @trace_level,
@@ -161,82 +161,97 @@ describe RightScale::ErrorTracker do
161
161
  @exception = RuntimeError.new("error")
162
162
  @tracker.init(@agent, @agent_name, @options)
163
163
  @cgi_data = @tracker.instance_variable_get(:@cgi_data)
164
+ ENV['RAILS_ENV'] = 'development'
164
165
  end
165
166
 
166
- it "sends notification using HydraulicBrake" do
167
- @brake.should_receive(:notify).with(on { |a| a[:error_message] == "error" &&
168
- a[:error_class] == "RuntimeError" &&
169
- a[:backtrace].nil? &&
170
- ["test", "development"].include?(a[:environment_name]) &&
171
- a[:cgi_data].should == @cgi_data &&
172
- a.keys & [:component, :action, :parameters, :session_data] == [] }).once
167
+ after(:each) do
168
+ ENV['RAILS_ENV'] = nil
169
+ end
170
+
171
+ it "sends notification using Airbrake" do
172
+ @brake.should_receive(:notify).with(on { |a|
173
+ a[:errors].first[:type] == "RuntimeError" &&
174
+ a[:environment] == @cgi_data
175
+ }, {}, :right_agent).once
173
176
  @tracker.notify(@exception).should be true
174
177
  end
175
178
 
176
179
  it "includes packet data in notification" do
177
180
  request = RightScale::Request.new("/foo/bar", {:pay => "load"}, :token => "token")
178
- @brake.should_receive(:notify).with(on { |a| a[:error_message] == "error" &&
179
- a[:error_class] == "RuntimeError" &&
180
- a[:backtrace].nil? &&
181
- a[:action] == "bar" &&
182
- a[:parameters] == {:pay => "load"} &&
183
- ["test", "development"].include?(a[:environment_name]) &&
184
- a[:cgi_data] == @cgi_data &&
185
- a[:session_data] == {:uuid => "token"} }).once
181
+ @brake.should_receive(:notify).with(on { |a|
182
+ a[:errors].first[:message] == "error" &&
183
+ a[:context][:action] == 'bar' &&
184
+ a[:params] == { :pay => 'load' } &&
185
+ a[:session] == { :uuid => 'token' }
186
+ }, {}, :right_agent).once
187
+
186
188
  @tracker.notify(@exception, request).should be true
187
189
  end
188
190
 
189
191
  it "includes event data in notification" do
190
- @brake.should_receive(:notify).with(on { |a| a[:error_message] == "error" &&
191
- a[:error_class] == "RuntimeError" &&
192
- a[:backtrace].nil? &&
193
- a[:action] == "bar" &&
194
- a[:parameters] == {:pay => "load"} &&
195
- ["test", "development"].include?(a[:environment_name]) &&
196
- a[:cgi_data] == @cgi_data &&
197
- a[:session_data] == {:uuid => "token"} }).once
192
+ @brake.should_receive(:notify).with(on { |a|
193
+ a[:errors].first[:message] == "error" &&
194
+ a[:errors].first[:type] == "RuntimeError" &&
195
+ a[:context][:action] == 'bar' &&
196
+ a[:params] == { :pay => 'load' } &&
197
+ a[:session] == { :uuid => 'token' }
198
+ }, {}, :right_agent).once
199
+
198
200
  @tracker.notify(@exception, {"uuid" => "token", "path" => "/foo/bar", "data" => {:pay => "load"}}).should be true
199
201
  end
200
202
 
201
203
  it "adds agent class to :cgi_data in notification" do
202
- @brake.should_receive(:notify).with(on { |a| a[:cgi_data] == @cgi_data.merge(:agent_class => "AgentMock") }).once
204
+ @brake.should_receive(:notify).with(on { |a|
205
+ a[:environment] == @cgi_data.merge(:agent_class => 'AgentMock')
206
+ }, {}, :right_agent).once
207
+
203
208
  @tracker.notify(@exception, packet = nil, @agent).should be true
204
209
  end
205
210
 
206
211
  it "adds component to notification" do
207
- @brake.should_receive(:notify).with(on { |a| a[:component] == "component" }).once
212
+ @brake.should_receive(:notify).with(on { |a|
213
+ a[:context][:component] == 'component'
214
+ }, {}, :right_agent).once
208
215
  @tracker.notify(@exception, packet = nil, agent = nil, "component").should be true
209
216
  end
210
217
 
211
218
  it "converts non-nil, non-hash payload in packet to a hash" do
212
219
  request = RightScale::Request.new("/foo/bar", "payload", :token => "token")
213
- @brake.should_receive(:notify).with(on { |a| a[:parameters] == {:param => "payload"} }).once
220
+ @brake.should_receive(:notify).with(on { |a|
221
+ a[:params] == { :param => 'payload' }
222
+ }, {}, :right_agent).once
214
223
  @tracker.notify(@exception, request).should be true
215
224
  end
216
225
 
217
226
  it "converts non-nil, non-hash data in event to a hash" do
218
- @brake.should_receive(:notify).with(on { |a| a[:parameters] == {:param => "payload"} }).once
227
+ @brake.should_receive(:notify).with(on { |a|
228
+ a[:params] == { :param => 'payload' }
229
+ }, {}, :right_agent).once
219
230
  @tracker.notify(@exception, {"uuid" => "token", "path" => "/foo/bar", "data" => "payload"}).should be true
220
231
  end
221
232
 
222
233
  it "omits :parameters from notification if payload in packet is nil" do
223
234
  request = RightScale::Request.new("/foo/bar", nil, :token => "token")
224
- @brake.should_receive(:notify).with(on { |a| !a.has_key?(:parameters) }).once
235
+ @brake.should_receive(:notify).with(on { |a|
236
+ a[:params] == {}
237
+ }, {}, :right_agent).once
225
238
  @tracker.notify(@exception, request).should be true
226
239
  end
227
240
 
228
241
  it "omits :parameters from notification if data in packet is nil" do
229
- @brake.should_receive(:notify).with(on { |a| !a.has_key?(:parameters) }).once
242
+ @brake.should_receive(:notify).with(on { |a|
243
+ a[:params] == {}
244
+ }, {}, :right_agent).once
230
245
  @tracker.notify(@exception, {"uuid" => "token", "path" => "/foo/bar", "data" => nil}).should be true
231
246
  end
232
247
 
233
248
  it "functions even if cgi_data has not been initialized by notify_init" do
234
249
  @tracker.instance_variable_set(:@cgi_data, nil)
235
- @brake.should_receive(:notify).with(on { |a| a[:error_message] == "error" &&
236
- a[:error_class] == "RuntimeError" &&
237
- a[:backtrace].nil? &&
238
- ["test", "development"].include?(a[:environment_name]) &&
239
- a.keys & [:cgi_data, :component, :action, :parameters, :session_data] == [] }).once
250
+ @brake.should_receive(:notify).with(on { |a|
251
+ a[:errors].first[:message] == "error" &&
252
+ a[:errors].first[:type] == "RuntimeError" &&
253
+ a[:environment] == {}
254
+ }, {}, :right_agent).once
240
255
  @tracker.notify(@exception).should be true
241
256
  end
242
257
 
@@ -285,7 +300,7 @@ describe RightScale::ErrorTracker do
285
300
 
286
301
  context :notify_init do
287
302
  class ConfigMock
288
- attr_accessor :secure, :host, :port, :api_key, :project_root
303
+ attr_accessor :host, :api_key, :project_id, :project_key, :root_directory, :environment
289
304
  end
290
305
 
291
306
  it "does not initialize if Airbrake endpoint or API key is undefined" do
@@ -296,7 +311,10 @@ describe RightScale::ErrorTracker do
296
311
  @tracker.instance_variable_get(:@notify_enabled).should be false
297
312
  end
298
313
 
299
- it "initializes cgi data and configures HydraulicBrake" do
314
+ it "initializes cgi data and configures Airbrake" do
315
+ # dirty, but we need to make sure this is unset in order to progress
316
+ Airbrake.instance_variable_set(:@notifiers, {})
317
+
300
318
  config = ConfigMock.new
301
319
  @brake.should_receive(:configure).and_yield(config).once
302
320
  @tracker.send(:notify_init, @agent_name, @options).should be true
@@ -305,20 +323,19 @@ describe RightScale::ErrorTracker do
305
323
  cgi_data[:pid].should be_a Integer
306
324
  cgi_data[:process].should be_a String
307
325
  cgi_data[:shard_id].should == @shard_id
308
- config.secure.should be true
309
- config.host.should == "airbrake.com"
310
- config.port.should == 443
311
- config.api_key.should == @api_key
312
- config.project_root.should be_a String
326
+ config.host.should == "https://airbrake.com"
327
+ config.project_id.should == @api_key
328
+ config.project_key.should == @api_key
329
+ config.root_directory.should be_a String
313
330
  @tracker.instance_variable_get(:@notify_enabled).should be true
314
331
  @tracker.instance_variable_get(:@filter_params).should == ["password"]
315
332
  end
316
333
 
317
- it "raises exception if hydraulic_gem is not available" do
318
- flexmock(@tracker).should_receive(:require_succeeds?).with("hydraulic_brake").and_return(false)
334
+ it "raises exception if airbrake-ruby is not available" do
335
+ flexmock(@tracker).should_receive(:require_succeeds?).with("airbrake-ruby").and_return(false)
319
336
  lambda do
320
337
  @tracker.send(:notify_init, @agent_name, @options)
321
- end.should raise_error(RuntimeError, /hydraulic_brake gem missing/)
338
+ end.should raise_error(RuntimeError, /airbrake-ruby gem missing/)
322
339
  end
323
340
  end
324
341
 
@@ -23,6 +23,12 @@
23
23
  require 'rubygems'
24
24
  require 'bundler/setup'
25
25
 
26
+ begin
27
+ require 'pry'
28
+ rescue LoadError
29
+ #no-op; optional dependency
30
+ end
31
+
26
32
  require 'rspec'
27
33
  require 'flexmock'
28
34
  require 'simplecov'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: right_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.3
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Kirchhoff
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2015-09-16 00:00:00.000000000 Z
14
+ date: 2016-05-20 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: right_support
@@ -116,9 +116,6 @@ dependencies:
116
116
  - - "~>"
117
117
  - !ruby/object:Gem::Version
118
118
  version: '2.3'
119
- - - "<"
120
- - !ruby/object:Gem::Version
121
- version: '2.4'
122
119
  type: :runtime
123
120
  prerelease: false
124
121
  version_requirements: !ruby/object:Gem::Requirement
@@ -126,9 +123,6 @@ dependencies:
126
123
  - - "~>"
127
124
  - !ruby/object:Gem::Version
128
125
  version: '2.3'
129
- - - "<"
130
- - !ruby/object:Gem::Version
131
- version: '2.4'
132
126
  - !ruby/object:Gem::Dependency
133
127
  name: ffi
134
128
  requirement: !ruby/object:Gem::Requirement
@@ -376,8 +370,6 @@ files:
376
370
  - spec/serialize/secure_serializer_spec.rb
377
371
  - spec/serialize/serializable_spec.rb
378
372
  - spec/serialize/serializer_spec.rb
379
- - spec/spec.opts
380
- - spec/spec.win32.opts
381
373
  - spec/spec_helper.rb
382
374
  - spec/tracer_spec.rb
383
375
  homepage: https://github.com/rightscale/right_agent
@@ -403,9 +395,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
403
395
  version: '0'
404
396
  requirements: []
405
397
  rubyforge_project:
406
- rubygems_version: 2.2.2
398
+ rubygems_version: 2.2.5
407
399
  signing_key:
408
400
  specification_version: 4
409
401
  summary: Agent for interfacing server with RightScale system
410
402
  test_files: []
411
- has_rdoc: true
@@ -1,2 +0,0 @@
1
- --colour
2
- --format=nested
@@ -1 +0,0 @@
1
- --format=nested