rearview 1.1.2-jruby → 1.2.0-jruby

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -3
  3. data/app/controllers/rearview/application_controller.rb +11 -0
  4. data/app/controllers/rearview/dashboard_children_controller.rb +1 -1
  5. data/app/controllers/rearview/dashboards_controller.rb +1 -1
  6. data/app/controllers/rearview/home_controller.rb +1 -1
  7. data/app/controllers/rearview/jobs_controller.rb +33 -29
  8. data/app/controllers/rearview/monitor_controller.rb +16 -2
  9. data/app/controllers/rearview/user_controller.rb +2 -2
  10. data/app/helpers/rearview/application_helper.rb +3 -3
  11. data/app/mailers/rearview/alert_mailer.rb +0 -2
  12. data/app/mailers/rearview/metrics_validation_mailer.rb +12 -0
  13. data/app/models/rearview/job.rb +17 -13
  14. data/app/views/rearview/home/show.html.erb +2 -0
  15. data/app/views/rearview/jobs/_job.json.jbuilder +1 -0
  16. data/app/views/rearview/metrics_validation_mailer/validation_failed_email.text.erb +13 -0
  17. data/app/views/rearview/monitor/create.json.jbuilder +1 -0
  18. data/db/migrate/20131106162900_base_schema.rb +2 -2
  19. data/lib/generators/templates/rearview.rb +24 -7
  20. data/lib/graphite.rb +13 -0
  21. data/lib/graphite/cacerts.pem +2184 -0
  22. data/lib/graphite/client.rb +44 -0
  23. data/lib/graphite/graph.rb +35 -0
  24. data/lib/{rearview/graphite_parser.rb → graphite/raw_parser.rb} +2 -3
  25. data/lib/graphite/target.rb +9 -0
  26. data/lib/graphite/target_grammer.rb +114 -0
  27. data/lib/graphite/target_grammer.treetop +53 -0
  28. data/lib/graphite/target_parser.rb +50 -0
  29. data/lib/graphite/treetop_ext.rb +14 -0
  30. data/lib/rearview.rb +11 -3
  31. data/lib/rearview/alerts_handler.rb +2 -6
  32. data/lib/rearview/configuration.rb +44 -19
  33. data/lib/rearview/cron_expression_validator.rb +11 -0
  34. data/lib/rearview/metrics_validator.rb +52 -0
  35. data/lib/rearview/metrics_validator_service.rb +24 -0
  36. data/lib/rearview/metrics_validator_task.rb +56 -0
  37. data/lib/rearview/monitor_runner.rb +9 -7
  38. data/lib/rearview/monitor_service.rb +2 -0
  39. data/lib/rearview/stats_service.rb +4 -2
  40. data/lib/rearview/version.rb +1 -1
  41. data/lib/tasks/rearview_tasks.rake +7 -1
  42. data/public/{help → rearview-src/help}/alert.html +0 -0
  43. data/public/{help → rearview-src/help}/quick.html +0 -0
  44. data/public/rearview-src/js/app.js +9 -0
  45. data/public/rearview-src/js/model/user.js +6 -2
  46. data/public/rearview-src/js/view/addmonitor.js +13 -8
  47. data/public/rearview-src/js/view/alert.js +11 -4
  48. data/public/rearview-src/js/view/dashboard.js +4 -2
  49. data/public/rearview-src/js/view/expandedmonitor.js +22 -9
  50. data/public/rearview-src/js/view/settings.js +84 -0
  51. data/public/rearview-src/less/login.less +4 -4
  52. data/public/rearview-src/less/rearview.less +17 -10
  53. data/public/{monitors → rearview-src/monitors}/index.json +1 -1
  54. data/public/{monitors → rearview-src/monitors}/outage.rb +0 -0
  55. data/public/rearview-src/templates/alert.hbs +10 -2
  56. data/public/rearview-src/templates/primarynav.hbs +6 -6
  57. data/public/rearview-src/templates/schedulemonitor.hbs +2 -1
  58. data/public/rearview-src/templates/settings.hbs +23 -0
  59. data/public/rearview/build.txt +1 -0
  60. data/public/rearview/help/alert.html +20 -0
  61. data/public/rearview/help/quick.html +34 -0
  62. data/public/rearview/js/app.js +1 -1
  63. data/public/rearview/js/main.js +21 -21
  64. data/public/rearview/js/model/user.js +1 -1
  65. data/public/rearview/js/view/addmonitor.js +1 -1
  66. data/public/rearview/js/view/alert.js +1 -1
  67. data/public/rearview/js/view/dashboard.js +1 -1
  68. data/public/rearview/js/view/expandedmonitor.js +1 -1
  69. data/public/rearview/js/view/settings.js +1 -0
  70. data/public/rearview/less/login.less +4 -4
  71. data/public/rearview/less/rearview.less +17 -10
  72. data/public/rearview/monitors/index.json +3 -0
  73. data/public/rearview/monitors/outage.rb +2 -0
  74. data/public/rearview/templates/alert.hbs +10 -2
  75. data/public/rearview/templates/primarynav.hbs +6 -6
  76. data/public/rearview/templates/schedulemonitor.hbs +2 -1
  77. data/public/rearview/templates/settings.hbs +23 -0
  78. data/spec/controllers/jobs_controller_spec.rb +1 -0
  79. data/spec/controllers/monitor_controller_spec.rb +3 -0
  80. data/spec/controllers/user_controller_spec.rb +5 -2
  81. data/spec/data/metrics.yml +598 -0
  82. data/spec/dummy/log/development.log +1044 -0
  83. data/spec/dummy/log/test.log +171716 -0
  84. data/spec/helpers/application_helper_spec.rb +33 -0
  85. data/spec/lib/graphite/client_spec.rb +126 -0
  86. data/spec/lib/graphite/graph_spec.rb +17 -0
  87. data/spec/lib/graphite/graphite_spec.rb +4 -0
  88. data/spec/lib/{rearview/graphite_parser_spec.rb → graphite/raw_parser.rb} +6 -5
  89. data/spec/lib/graphite/target_grammer_spec.rb +106 -0
  90. data/spec/lib/graphite/target_parser_spec.rb +124 -0
  91. data/spec/lib/graphite/target_spec.rb +5 -0
  92. data/spec/lib/rearview/configuration_spec.rb +69 -48
  93. data/spec/lib/rearview/metrics_validator_service_spec.rb +43 -0
  94. data/spec/lib/rearview/metrics_validator_spec.rb +84 -0
  95. data/spec/lib/rearview/metrics_validator_task_spec.rb +62 -0
  96. data/spec/lib/rearview/monitor_runner_spec.rb +3 -3
  97. data/spec/lib/rearview/stats_task_spec.rb +21 -0
  98. data/spec/mailers/metrics_validation_mailer_spec.rb +46 -0
  99. data/spec/models/job_spec.rb +82 -9
  100. data/spec/spec_helper.rb +15 -4
  101. data/spec/support/json_factory.rb +1 -1
  102. data/spec/views/dashboards/show.json.jbuilder_spec.rb +3 -1
  103. data/spec/views/jobs/show.json.jbuilder_spec.rb +2 -1
  104. metadata +98 -11
  105. data/public/rearview-src/templates/test.txt +0 -1
  106. data/public/rearview/templates/test.txt +0 -1
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Graphite::Target do
4
+ end
5
+
@@ -9,65 +9,85 @@ describe Rearview::Configuration do
9
9
  let(:config) { Rearview::Configuration.new }
10
10
 
11
11
  context 'validation' do
12
- it { should validate_presence_of(:graphite_url) }
13
- it { should validate_presence_of(:pagerduty_url) }
14
12
  it { should validate_presence_of(:default_from) }
15
- it { should validate_presence_of(:sandbox_dir) }
16
13
  it { should validate_presence_of(:sandbox_exec) }
17
14
  it { should validate_presence_of(:sandbox_timeout) }
18
15
  it { should validate_presence_of(:default_url_options) }
19
16
  it { should validate_presence_of(:authentication) }
20
17
  it { should validate_numericality_of(:sandbox_timeout).is_greater_than(4) }
21
- it "should requre sandbox_dir to be a directory" do
22
- config.sandbox_dir="/__not_likely__"
23
- config.valid?
24
- expect(config.errors[:sandbox_dir]).to include("is not a directory")
25
- config.sandbox_dir = File.dirname(__FILE__)
26
- config.valid?
27
- expect(config.errors[:sandbox_dir]).to be_empty
18
+ context 'sandbox_dir' do
19
+ it { should validate_presence_of(:sandbox_dir) }
20
+ it "should be a directory" do
21
+ config.sandbox_dir="/__not_likely__"
22
+ config.valid?
23
+ expect(config.errors[:sandbox_dir]).to include("is not a directory")
24
+ config.sandbox_dir = File.dirname(__FILE__)
25
+ config.valid?
26
+ expect(config.errors[:sandbox_dir]).to be_empty
27
+ end
28
28
  end
29
- it "should require graphite_url to be a url" do
30
- response = stub(code: 200)
31
- HTTParty.stubs(:get).returns(response)
32
- config.graphite_url="ssh://fooblah"
33
- config.valid?
34
- expect(config.errors[:graphite_url]).to include("is not a valid URL")
35
- config.graphite_url="fooblah"
36
- config.valid?
37
- expect(config.errors[:graphite_url]).to include("is not a valid URL")
38
- config.graphite_url="http://fooblah.com"
39
- config.valid?
40
- expect(config.errors[:graphite_url]).to be_empty
29
+ context 'graphite_connection' do
30
+ it { should validate_presence_of(:graphite_connection) }
31
+ it "should require url option to be a valid url" do
32
+ config.graphite_connection = { url: 'ssh://fooblah' }
33
+ config.valid?
34
+ expect(config.errors[:graphite_connection]).to include("does not contain a valid URL")
35
+ end
36
+ it "should require url option to be present" do
37
+ config.graphite_connection = { url: nil }
38
+ config.valid?
39
+ expect(config.errors[:graphite_connection]).to include("graphite URL can't be blank")
40
+ end
41
+ pending do
42
+ it "should require url option to be reachable" do
43
+ config.graphite_connection = { url: 'http://graphite6.graphitehosting.com' }
44
+ config.valid?
45
+ mock_client = mock(:reachable? => false)
46
+ Graphite::Client.expects(:new).returns(mock_client)
47
+ expect(config.errors[:graphite_connection]).to include("graphite cannot be reached")
48
+ end
49
+ end
41
50
  end
42
- it "should require pagerduty_url to be a url" do
43
- config.pagerduty_url="ftp://fooblah"
44
- config.valid?
45
- expect(config.errors[:pagerduty_url]).to include("is not a valid URL")
46
- config.pagerduty_url="HTTPS://fooblah"
47
- config.valid?
48
- expect(config.errors[:pagerduty_url]).to be_empty
51
+ context 'pagerduty_url' do
52
+ it { should validate_presence_of(:pagerduty_url) }
53
+ it "should require pagerduty_url to be a url" do
54
+ config.pagerduty_url="ftp://fooblah"
55
+ config.valid?
56
+ expect(config.errors[:pagerduty_url]).to include("is not a valid URL")
57
+ config.pagerduty_url="HTTPS://fooblah"
58
+ config.valid?
59
+ expect(config.errors[:pagerduty_url]).to be_empty
60
+ end
49
61
  end
50
- it "should require graphite_url to be reachable" do
51
- response = stub(code: 400)
52
- HTTParty.expects(:get).with("http://graphite.mycompany-unreachable.com").returns(response)
53
- config.graphite_url="http://graphite.mycompany-unreachable.com"
54
- config.valid?
55
- expect(config.errors[:graphite_url]).to include("is not a reachable URL")
56
- response = stub(code: 200)
57
- HTTParty.expects(:get).with("http://graphite.mycompany.com").returns(response)
58
- config.graphite_url="http://graphite.mycompany.com"
59
- config.valid?
60
- expect(config.errors[:graphite_url]).to be_empty
62
+ context 'statsd_connection' do
63
+ it "should be present if stats are enabled" do
64
+ config.enable_stats = false
65
+ config.valid?
66
+ expect(config.errors[:statsd_connection]).to be_empty
67
+ config.enable_stats = true
68
+ config.valid?
69
+ expect(config.errors[:statsd_connection]).to include("can't be blank")
70
+ end
61
71
  end
62
- it "should require statsd_connection to be present if stats are enabled" do
63
- config.enable_stats = false
64
- config.valid?
65
- expect(config.errors[:statsd_connection]).to be_empty
66
- config.enable_stats = true
67
- config.valid?
68
- expect(config.errors[:statsd_connection]).to include("can't be blank")
72
+ context 'metrics_validator_schedule' do
73
+ it {
74
+ Rearview::Configuration.any_instance.stubs(:metrics_validator_enabled?).returns(true)
75
+ should_not allow_value('abc').for(:metrics_validator_schedule)
76
+ }
77
+ it {
78
+ Rearview::Configuration.any_instance.stubs(:metrics_validator_enabled?).returns(true)
79
+ should allow_value('0 * * * * ?').for(:metrics_validator_schedule)
80
+ }
81
+ it "should be present if metrics_validator is enabled" do
82
+ config.enable_metrics_validator = false
83
+ config.valid?
84
+ expect(config.errors[:metrics_validator_schedule]).to be_empty
85
+ config.enable_metrics_validator = true
86
+ config.metrics_validator_schedule = nil
87
+ config.valid?
88
+ expect(config.errors[:metrics_validator_schedule]).to include("can't be blank")
89
+ end
69
90
  end
70
- pending "should require sanbox_exec to be executable"
71
91
  end
72
92
 
73
93
  context '.new' do
@@ -80,6 +100,7 @@ describe Rearview::Configuration do
80
100
  expect(config.enable_monitor).to be_true
81
101
  expect(config.enable_stats).to be_false
82
102
  expect(config.verify).to be_false
103
+ expect(config.graphite_connection).to eq({})
83
104
  expect(config.authentication).to eq({strategy: :database})
84
105
  expect(config.default_url_options).to eq({:host=>"localhost", :port=>"3000"})
85
106
  end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rearview::MetricsValidatorService do
4
+ before do
5
+ Celluloid.shutdown
6
+ Celluloid.boot
7
+ @service = Rearview::MetricsValidatorService.new
8
+ end
9
+ context '#startup' do
10
+ it "can only be started if stopped" do
11
+ Rearview::MetricsValidatorTask.stubs(:supervise).returns(mock)
12
+ @service.startup
13
+ expect { @service.startup }.to raise_error("service already started")
14
+ end
15
+ it "should create the supervised task" do
16
+ Rearview::MetricsValidatorTask.expects(:supervise)
17
+ @service.startup
18
+ end
19
+ end
20
+ context '#shutdown' do
21
+ it "can only be shutdown if started" do
22
+ expect { @service.shutdown }.to raise_error("service not started")
23
+ end
24
+ it "should terminate the supervised task" do
25
+ mock_task = mock
26
+ mock_task.expects(:terminate).once
27
+ Rearview::MetricsValidatorTask.stubs(:supervise).returns(stub(:actors => stub(:first => mock_task)))
28
+ @service.startup
29
+ @service.shutdown
30
+ end
31
+ end
32
+ context '#started?' do
33
+ it "should be true if the service is started" do
34
+ Rearview::MetricsValidatorTask.stubs(:supervise).returns(mock)
35
+ @service.startup
36
+ expect(@service.started?).to be_true
37
+ end
38
+ it "should be false if the service is not started" do
39
+ expect(@service.started?).to be_false
40
+ end
41
+ end
42
+ end
43
+
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rearview::MetricsValidator do
4
+
5
+ context '#metric_valid?' do
6
+ let(:metrics_validator) { Rearview::MetricsValidator.new({ attributes: [:metrics] })}
7
+ context 'true' do
8
+ it 'when the metric is commented out' do
9
+ expect(metrics_validator.metric_valid?('#stats_count.foo')).to be_true
10
+ end
11
+ it 'when the metric is complex' do
12
+ mock_client = mock(:metric_exists? => true)
13
+ metrics_validator.stubs(:client).returns(mock_client)
14
+ expect(metrics_validator.metric_valid?(%q[alias(summarize(stats_counts.watson.summary_tables.run,"5min"),"Daily Watson Tables so far")])).to be_true
15
+ end
16
+ end
17
+ context 'false' do
18
+ it 'when the metric is not parseable' do
19
+ expect(metrics_validator.metric_valid?(%q[alias@(stats.x.y,"processed")])).to be_false
20
+ end
21
+ it 'when the metric cannot be extracted' do
22
+ mock_parser = mock
23
+ mock_parser.stubs(:parse)
24
+ mock_parser.stubs(:error?).returns(false)
25
+ mock_parser.stubs(:tree).returns(mock(:comment? => false,:metric => nil))
26
+ metrics_validator.stubs(:target_parser).returns(mock_parser)
27
+ expect(metrics_validator.metric_valid?('stats.garbage.ignored')).to be_false
28
+ end
29
+ end
30
+ end
31
+ context '#validate_each' do
32
+ let(:job) { FactoryGirl.create(:job) }
33
+ let(:metrics_validator) { Rearview::MetricsValidator.new({ attributes: [:metrics] })}
34
+ context 'valid' do
35
+ it 'parses the metric' do
36
+ mock_client = mock(:metric_exists? => true)
37
+ metrics_validator.stubs(:client).returns(mock_client)
38
+ expect(metrics_validator.metric_valid?(%q[alias(summarize(stats_counts.watson.summary_tables.run,"5min"),"Daily Watson Tables so far")])).to be_true
39
+ end
40
+ it 'when all metrics exists' do
41
+ mock_client = mock(:metric_exists? => true)
42
+ metrics_validator.stubs(:client).returns(mock_client)
43
+ metrics_validator.validate_each(job,:metrics,job.metrics)
44
+ expect(job.errors[:metrics]).to be_empty
45
+ end
46
+ end
47
+ context 'invalid' do
48
+ it 'when one metric does not exist' do
49
+ job.metrics << "metric.fooey"
50
+ mock_client = mock
51
+ mock_client.expects(:metric_exists?).with("metric.fooey").returns(false)
52
+ mock_client.expects(:metric_exists?).with(job.metrics.first).returns(true)
53
+ metrics_validator.stubs(:client).returns(mock_client)
54
+ metrics_validator.validate_each(job,:metrics,job.metrics)
55
+ expect(job.errors[:metrics]).to include("contains an invalid metric: metric.fooey")
56
+ expect(job.errors[:metrics]).not_to include("contains an invalid metric: #{job.metrics.first}")
57
+ end
58
+ end
59
+ context 'cache' do
60
+ context 'enabled' do
61
+ let(:caching_validator) { Rearview::MetricsValidator.new({ attributes: [:metrics], cache: true })}
62
+ it 'caches responses for metrics' do
63
+ job.metrics << job.metrics.first
64
+ mock_client = mock
65
+ mock_client.expects(:metric_exists?).with(job.metrics.first).once.returns(true)
66
+ caching_validator.stubs(:client).returns(mock_client)
67
+ caching_validator.validate_each(job,:metrics,job.metrics)
68
+ expect(job.errors[:metrics]).to be_empty
69
+ end
70
+ end
71
+ context 'disabled' do
72
+ it 'does not cache responses for metrics' do
73
+ job.metrics << job.metrics.first
74
+ mock_client = mock
75
+ mock_client.expects(:metric_exists?).with(job.metrics.first).twice.returns(true)
76
+ metrics_validator.stubs(:client).returns(mock_client)
77
+ metrics_validator.validate_each(job,:metrics,job.metrics)
78
+ expect(job.errors[:metrics]).to be_empty
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rearview::MetricsValidatorTask do
4
+
5
+ before do
6
+ now = Time.now
7
+ Timecop.freeze(Time.local(now.year,now.mon,now.day))
8
+ end
9
+
10
+ context '.initialize' do
11
+ it 'schedules itself by default' do
12
+ Rearview::MetricsValidatorTask.any_instance.expects(:schedule)
13
+ Rearview::MetricsValidatorTask.new('0 * * * * ?')
14
+ end
15
+ end
16
+
17
+ context '#schedule' do
18
+ it 'sets the delay to 60s if the cron expression is \'0 * * * * ?\'' do
19
+ task = Rearview::MetricsValidatorTask.new('0 * * * * ?',false)
20
+ task.expects(:after).with(60.0).once
21
+ task.schedule
22
+ end
23
+ it 'sets the delay to 300s if the cron expression is \'0 5 * * * ?\'' do
24
+ task = Rearview::MetricsValidatorTask.new('0 5 * * * ?',false)
25
+ task.expects(:after).with(300.0).once
26
+ task.schedule
27
+ end
28
+ end
29
+
30
+ context '.run' do
31
+ let(:job1_invalid) {
32
+ job = FactoryGirl.create(:job)
33
+ job.errors.add(:metrics,"contains an invalid metric: #{job.metrics.first}")
34
+ job
35
+ }
36
+ let(:job2_valid) {
37
+ FactoryGirl.create(:job)
38
+ }
39
+ let(:job3_invalid) {
40
+ job = FactoryGirl.create(:job)
41
+ job.errors.add(:metrics,"contains an invalid metric: #{job.metrics.first}")
42
+ job
43
+ }
44
+ it 'still schedules if there is an exception' do
45
+ Rearview::Job.stubs(:schedulable).raises(StandardError,"oops")
46
+ task = Rearview::MetricsValidatorTask.new('0 5 * * * ?',false)
47
+ task.expects(:schedule).once
48
+ task.run
49
+ end
50
+ it 'mails alerts only for jobs with invalid metrics' do
51
+ Rearview::Job.stubs(:schedulable).returns(mock(:load => [job1_invalid,job2_valid,job3_invalid]))
52
+ Rearview::MetricsValidator.any_instance.stubs(:validate_each)
53
+ task = Rearview::MetricsValidatorTask.new('0 5 * * * ?',false)
54
+ task.expects(:schedule).once
55
+ task.expects(:alert_validation_failed).with(job1_invalid).once
56
+ task.expects(:alert_validation_failed).with(job2_valid).never
57
+ task.expects(:alert_validation_failed).with(job3_invalid).once
58
+ task.run
59
+ end
60
+ end
61
+
62
+ end
@@ -2,9 +2,9 @@ require 'spec_helper'
2
2
 
3
3
  describe Rearview::MonitorRunner, :travis=>true do
4
4
 
5
- artifact1 = Rearview::GraphiteParser.parse open("spec/data/monitor.dat").read
6
- artifact2 = Rearview::GraphiteParser.parse open("spec/data/test.dat").read
7
- artifact3 = Rearview::GraphiteParser.parse open("spec/data/large_set.dat").read
5
+ artifact1 = Graphite::RawParser.parse open("spec/data/monitor.dat").read
6
+ artifact2 = Graphite::RawParser.parse open("spec/data/test.dat").read
7
+ artifact3 = Graphite::RawParser.parse open("spec/data/large_set.dat").read
8
8
 
9
9
  context 'create_from_to_dates' do
10
10
  before do
@@ -39,6 +39,27 @@ describe Rearview::StatsTask do
39
39
  stats_task.statsd.expects(:batch)
40
40
  stats_task.run
41
41
  end
42
+ it "sends the correct stats" do
43
+ statsd = mock
44
+ batch = mock
45
+ statsd.expects(:batch_size=)
46
+ Rearview::Statsd.stubs(:new).returns(statsd)
47
+ stats_task = Rearview::StatsTask.new(120,false)
48
+ statsd.expects(:batch).yields(batch)
49
+ batch.expects(:gauge).with('vm.total_memory',any_parameters)
50
+ batch.expects(:gauge).with('vm.free_memory',any_parameters)
51
+ batch.expects(:gauge).with('vm.max_memory',any_parameters)
52
+ batch.expects(:gauge).with('vm.heap.committed',any_parameters)
53
+ batch.expects(:gauge).with('vm.heap.init',any_parameters)
54
+ batch.expects(:gauge).with('vm.heap.max',any_parameters)
55
+ batch.expects(:gauge).with('vm.heap.used',any_parameters)
56
+ batch.expects(:gauge).with('vm.non_heap.committed',any_parameters)
57
+ batch.expects(:gauge).with('vm.non_heap.init',any_parameters)
58
+ batch.expects(:gauge).with('vm.non_heap.max',any_parameters)
59
+ batch.expects(:gauge).with('vm.non_heap.used',any_parameters)
60
+ batch.expects(:gauge).with('monitor.total',any_parameters)
61
+ stats_task.run
62
+ end
42
63
  end
43
64
 
44
65
  end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rearview::MetricsValidationMailer do
4
+
5
+ let(:job) {
6
+ job = FactoryGirl.build(:job)
7
+ job.errors.add(:metrics,"contains an invalid metric: stats.my_count")
8
+ job
9
+ }
10
+
11
+ let(:mail) {
12
+ Rearview::MetricsValidationMailer.validation_failed_email("foo@foo.com",job)
13
+ }
14
+
15
+ context 'subject' do
16
+ it 'contains the job name' do
17
+ expect(mail.subject).to match(/#{job.name}/)
18
+ end
19
+ it 'contains subject tag' do
20
+ expect(mail.subject).to match(/\[Rearview ALERT\]/)
21
+ end
22
+ end
23
+
24
+ context 'body' do
25
+ it 'has the alert message' do
26
+ expect(mail.body.encoded).to match(/ALERT: Job has \(1\) invalid metric/)
27
+ end
28
+ it 'has the monitor name' do
29
+ expect(mail.body.encoded).to match(/Monitor: #{job.name}/)
30
+ end
31
+ it 'has the monitor description' do
32
+ expect(mail.body.encoded).to match(/Description: #{job.description}/)
33
+ end
34
+ it 'has the alerted on date' do
35
+ expect(mail.body.encoded).to match(/Alerted On: .*/)
36
+ end
37
+ it 'has a direct link' do
38
+ expect(mail.body.encoded).to match(%r{Direct Link: http://localhost:3000/rearview/#dash/#{job.app_id}/expand/#{job.id}})
39
+ end
40
+ it 'has the invalid metric name' do
41
+ expect(mail.body.encoded).to match(/^stats.my_count/)
42
+ end
43
+ end
44
+
45
+ end
46
+
@@ -10,26 +10,39 @@ describe Rearview::Job do
10
10
  end
11
11
 
12
12
  describe 'validations' do
13
- it { should validate_presence_of(:cron_expr) }
14
13
  it { should validate_presence_of(:name) }
15
14
  it { should validate_presence_of(:metrics) }
16
15
  it { should validate_presence_of(:app_id) }
17
- it { should_not allow_value('abc').for(:cron_expr) }
18
- it { should allow_value('0 * * * * ?').for(:cron_expr) }
19
16
  it { should ensure_inclusion_of(:status).in_array(Rearview::Job::Status.values) }
17
+ describe 'cron_expr' do
18
+ before do
19
+ Rearview::MetricsValidator.any_instance.stubs(:validate_each)
20
+ Rearview::Job.any_instance.stubs(:deep_validation?).returns(true)
21
+ end
22
+ it { should validate_presence_of(:cron_expr) }
23
+ it { should_not allow_value('abc').for(:cron_expr) }
24
+ it { should allow_value('0 * * * * ?').for(:cron_expr) }
25
+ end
20
26
  describe 'alert_keys' do
21
- let(:job) { create(:job) }
27
+ before do
28
+ Rearview::MetricsValidator.any_instance.stubs(:validate_each)
29
+ end
30
+ let(:job) {
31
+ job = create(:job)
32
+ job.deep_validation = true
33
+ job
34
+ }
22
35
  it "should require a valid URI" do
23
36
  keys = ["htptptptpt://not_a_uri"]
24
37
  job.alert_keys=keys
25
38
  expect(job.valid?).to be_false
26
- expect(job.errors[:alert_keys]).to include("invalid URI")
39
+ expect(job.errors[:alert_keys]).to include("#{keys.first} is an invalid URI")
27
40
  end
28
41
  it "should require it to be one of the supported schemes" do
29
42
  keys = ["http://www.google.com"]
30
43
  job.alert_keys=keys
31
44
  expect(job.valid?).to be_false
32
- expect(job.errors[:alert_keys]).to include("unsupported scheme")
45
+ expect(job.errors[:alert_keys]).to include("#{keys.first} is not a supported alert type")
33
46
  end
34
47
  it "should validate the scheme against the corresponding alert" do
35
48
  keys = ["pagerduty:10101010101010101010101010101010","mailto:first.last@hungrymachine.com","campfire://first.last@hungrymachine.com?token=123&room=text"]
@@ -40,19 +53,19 @@ describe Rearview::Job do
40
53
  keys = ["pagerduty:abcdefg"]
41
54
  job.alert_keys=keys
42
55
  expect(job.valid?).to be_false
43
- expect(job.errors[:alert_keys]).to include("pagerduty URI is invalid")
56
+ expect(job.errors[:alert_keys]).to include("#{keys.first} is invalid for supported alert type")
44
57
  end
45
58
  it "should detect an invalid mail URI" do
46
59
  keys = ["mailto:abcdefg"]
47
60
  job.alert_keys=keys
48
61
  expect(job.valid?).to be_false
49
- expect(job.errors[:alert_keys]).to include("mailto URI is invalid")
62
+ expect(job.errors[:alert_keys]).to include("#{keys.first} is invalid for supported alert type")
50
63
  end
51
64
  it "should detect an invalid campfire URI" do
52
65
  keys = ["campfire://first.last@hungrymachine.com"]
53
66
  job.alert_keys=keys
54
67
  expect(job.valid?).to be_false
55
- expect(job.errors[:alert_keys]).to include("campfire URI is invalid")
68
+ expect(job.errors[:alert_keys]).to include("#{keys.first} is invalid for supported alert type")
56
69
  end
57
70
  end
58
71
  end
@@ -133,13 +146,73 @@ describe Rearview::Job do
133
146
  inactive_job.sync_monitor_service
134
147
  end
135
148
  end
149
+ describe '#set_defaults' do
150
+ context 'alert_keys' do
151
+ it "should set it to an empty array if not present" do
152
+ job = create(:job, { alert_keys: nil})
153
+ job.save!
154
+ expect(job.alert_keys).to eq([])
155
+ job = create(:job)
156
+ expect(job.alert_keys).not_to eq([])
157
+ end
158
+ end
159
+ end
160
+ describe '#delay' do
161
+ before do
162
+ now = Time.now
163
+ Timecop.freeze(Time.local(now.year,now.mon,now.day))
164
+ end
165
+ after do
166
+ Timecop.return
167
+ end
168
+ it "cron expression '0 * * * * ?' to be 60.0" do
169
+ job = build(:job,cron_expr: '0 * * * * ?')
170
+ expect(job.delay).to eq(60.0)
171
+ end
172
+ it "any cron expression other than '0 * * * * ?' to be calculated by Rearview::CronHelper" do
173
+ job = build(:job,cron_expr: '0 30 * * * ?')
174
+ Rearview::CronHelper.expects(:next_valid_time_after).with('0 30 * * * ?')
175
+ job.delay
176
+ end
177
+ end
178
+ describe '#translate_associated_event' do
179
+ let(:transition) { mock }
180
+ let(:job) { create(:job) }
181
+ it 'echos back any non-security error' do
182
+ transition.stubs(:event).returns(:foo)
183
+ expect(job.send(:translate_associated_event,transition)).to eq(:foo)
184
+ end
185
+ it 'translates it to an :error' do
186
+ transition.stubs(:event).returns(:security_error)
187
+ expect(job.send(:translate_associated_event,transition)).to eq(:error)
188
+ end
189
+ end
136
190
  describe '#report_transition' do
191
+ let(:transition) { mock }
192
+ let(:job) { create(:job) }
193
+ before do
194
+ @statsd = mock
195
+ Rearview.config.stubs(:stats_enabled?).returns(true)
196
+ Rearview::Statsd.stubs(:statsd).returns(@statsd)
197
+ end
137
198
  context 'success event' do
138
199
  it "should increment monitor.success" do
200
+ transition.stubs(:event).returns(:success)
201
+ @statsd.expects(:increment).with("monitor.success")
202
+ job.send(:report_transition,transition)
139
203
  end
140
204
  end
141
205
  context 'failure event' do
142
206
  it "should increment monitor.failure" do
207
+ transition.stubs(:event).returns(:error)
208
+ @statsd.expects(:increment).with("monitor.failure")
209
+ job.send(:report_transition,transition)
210
+ end
211
+ end
212
+ context 'exception' do
213
+ it "should not raise" do
214
+ transition.stubs(:event).raises
215
+ expect{job.send(:report_transition,transition)}.not_to raise_error
143
216
  end
144
217
  end
145
218
  end