Commit ba398235a740b4902fc2993b45a8e2f82b4530dd
Exists in
master
and in
1 other branch
Merge branch 'notifications' of https://github.com/amaabca/errbit into amaabca-notifications
Conflicts: Gemfile.lock
Showing
25 changed files
with
224 additions
and
24 deletions
Show diff stats
Gemfile
| ... | ... | @@ -5,6 +5,9 @@ gem 'rails', '3.2.8' |
| 5 | 5 | gem 'nokogiri' |
| 6 | 6 | gem 'mongoid', '~> 2.4.10' |
| 7 | 7 | |
| 8 | +# force SSL | |
| 9 | +gem 'rack-ssl', :require => 'rack/ssl' | |
| 10 | + | |
| 8 | 11 | gem 'haml' |
| 9 | 12 | gem 'htmlentities', "~> 4.3.0" |
| 10 | 13 | |
| ... | ... | @@ -30,6 +33,7 @@ gem 'kaminari' |
| 30 | 33 | gem 'rack-ssl-enforcer' |
| 31 | 34 | gem 'fabrication', "~> 1.3.0" # Both for tests, and loading demo data |
| 32 | 35 | gem 'rails_autolink', '~> 1.0.9' |
| 36 | +gem 'campy' | |
| 33 | 37 | |
| 34 | 38 | platform :ruby do |
| 35 | 39 | gem 'mongo', '= 1.6.2' |
| ... | ... | @@ -45,7 +49,6 @@ group :development, :test do |
| 45 | 49 | gem 'webmock', :require => false |
| 46 | 50 | unless ENV["CI"] |
| 47 | 51 | gem 'ruby-debug', :platform => :mri_18 |
| 48 | - gem 'debugger', :platform => :mri_19 | |
| 49 | 52 | end |
| 50 | 53 | # gem 'rpm_contrib' |
| 51 | 54 | # gem 'newrelic_rpm' | ... | ... |
Gemfile.lock
| ... | ... | @@ -40,6 +40,8 @@ GEM |
| 40 | 40 | bson_ext (1.6.2) |
| 41 | 41 | bson (~> 1.6.2) |
| 42 | 42 | builder (3.0.3) |
| 43 | + campy (0.1.3) | |
| 44 | + multi_json (~> 1.0) | |
| 43 | 45 | capistrano (2.13.3) |
| 44 | 46 | highline |
| 45 | 47 | net-scp (>= 1.0.0) |
| ... | ... | @@ -62,13 +64,6 @@ GEM |
| 62 | 64 | rdoc |
| 63 | 65 | daemons (1.1.8) |
| 64 | 66 | database_cleaner (0.6.7) |
| 65 | - debugger (1.2.0) | |
| 66 | - columnize (>= 0.3.1) | |
| 67 | - debugger-linecache (~> 1.1.1) | |
| 68 | - debugger-ruby_core_source (~> 1.1.3) | |
| 69 | - debugger-linecache (1.1.2) | |
| 70 | - debugger-ruby_core_source (>= 1.1.1) | |
| 71 | - debugger-ruby_core_source (1.1.3) | |
| 72 | 67 | devise (1.5.3) |
| 73 | 68 | bcrypt-ruby (~> 3.0) |
| 74 | 69 | orm_adapter (~> 0.0.3) |
| ... | ... | @@ -289,10 +284,10 @@ DEPENDENCIES |
| 289 | 284 | actionmailer_inline_css (~> 1.3.0) |
| 290 | 285 | bson (= 1.6.2) |
| 291 | 286 | bson_ext (= 1.6.2) |
| 287 | + campy | |
| 292 | 288 | capistrano |
| 293 | 289 | capybara |
| 294 | 290 | database_cleaner (~> 0.6.0) |
| 295 | - debugger | |
| 296 | 291 | devise (~> 1.5.3) |
| 297 | 292 | email_spec |
| 298 | 293 | execjs |
| ... | ... | @@ -313,6 +308,7 @@ DEPENDENCIES |
| 313 | 308 | omniauth-github |
| 314 | 309 | oruen_redmine_client |
| 315 | 310 | pivotal-tracker |
| 311 | + rack-ssl | |
| 316 | 312 | rack-ssl-enforcer |
| 317 | 313 | rails (= 3.2.8) |
| 318 | 314 | rails_autolink (~> 1.0.9) | ... | ... |
3.19 KB
3.19 KB
2.8 KB
app/assets/javascripts/form.js
| ... | ... | @@ -8,6 +8,9 @@ $(function(){ |
| 8 | 8 | if($('div.issue_tracker.nested').length) |
| 9 | 9 | activateTypeSelector('issue_tracker', 'tracker_params'); |
| 10 | 10 | |
| 11 | + if($('div.notification_service.nested').length) | |
| 12 | + activateTypeSelector('notification_service', 'notification_params'); | |
| 13 | + | |
| 11 | 14 | $('body').addClass('has-js'); |
| 12 | 15 | $('.label_radio').click(function(){ |
| 13 | 16 | activateLabelIcons(); | ... | ... |
app/assets/stylesheets/application.css.erb
app/assets/stylesheets/errbit.css
| ... | ... | @@ -535,10 +535,11 @@ a.button.active { |
| 535 | 535 | display: inline-block; |
| 536 | 536 | } |
| 537 | 537 | |
| 538 | -/* Watchers and Issue Tracker Forms */ | |
| 539 | -div.watcher.nested .watcher_params, div.issue_tracker.nested .tracker_params { | |
| 538 | +/* Watchers / Issue Tracker / Notification Forms */ | |
| 539 | +div.watcher.nested .watcher_params, div.issue_tracker.nested .tracker_params, div.notification_service.nested .notification_params { | |
| 540 | 540 | display: none; |
| 541 | 541 | } |
| 542 | + | |
| 542 | 543 | div.nested .chosen { |
| 543 | 544 | display: block !important; |
| 544 | 545 | } |
| ... | ... | @@ -546,35 +547,35 @@ div.nested .choose { |
| 546 | 547 | margin-bottom: 0.5em; |
| 547 | 548 | } |
| 548 | 549 | |
| 549 | -div.issue_tracker.nested .choose { | |
| 550 | +div.issue_tracker.nested .choose, div.notification_service.nested .choose { | |
| 550 | 551 | background-color: #ebebeb; |
| 551 | 552 | border: 1px solid #dddddd; |
| 552 | 553 | margin: 0 0 15px; |
| 553 | 554 | padding: 12px; |
| 554 | 555 | } |
| 555 | -div.issue_tracker.nested img { | |
| 556 | +div.issue_tracker.nested img, div.notification_service.nested img { | |
| 556 | 557 | vertical-align: middle; |
| 557 | 558 | } |
| 558 | 559 | |
| 559 | 560 | /* Icons for Issue Tracker Radio Buttons */ |
| 560 | -div.issue_tracker.nested label.label_radio { | |
| 561 | +div.issue_tracker.nested label.label_radio, div.notification_service.nested label.label_radio { | |
| 561 | 562 | color: #929292; |
| 562 | 563 | padding-left: 33px; |
| 563 | 564 | margin-bottom: 6px; |
| 564 | 565 | margin-right: 8px; |
| 565 | 566 | line-height: 30px; |
| 566 | 567 | } |
| 567 | -div.issue_tracker.nested .choose { | |
| 568 | +div.issue_tracker.nested .choose, div.notification_service.nested .choose { | |
| 568 | 569 | padding-bottom: 6px; |
| 569 | 570 | } |
| 570 | -div.issue_tracker.nested label.label_radio:hover { | |
| 571 | +div.issue_tracker.nested label.label_radio:hover, div.notification_service.nested label.label_radio:hover { | |
| 571 | 572 | color: #696969; |
| 572 | 573 | } |
| 573 | -div.issue_tracker.nested .label_radio input { | |
| 574 | +div.issue_tracker.nested .label_radio input, div.notification_service.nested .label_radio input { | |
| 574 | 575 | position: absolute; left: -9999px; |
| 575 | 576 | } |
| 576 | 577 | |
| 577 | -div.issue_tracker.nested label.r_on, div.issue_tracker.nested label.r_on:hover { | |
| 578 | +div.issue_tracker.nested label.r_on, div.issue_tracker.nested label.r_on:hover, div.notification_service.nested label.r_on, div.notification_service.nested label.r_on:hover { | |
| 578 | 579 | color: #191919; |
| 579 | 580 | } |
| 580 | 581 | ... | ... |
app/assets/stylesheets/issue_tracker_icons.css.erb
| 1 | 1 | /* Issue Tracker inactive, select, create and goto icons */ |
| 2 | 2 | <% trackers = IssueTracker.subclasses.map{|t| t.label } << 'none' %> |
| 3 | + | |
| 3 | 4 | <% trackers.each do |tracker| %> |
| 4 | 5 | div.issue_tracker.nested label.<%= tracker %> { |
| 5 | 6 | background: url(/assets/<%= tracker %>_inactive.png) no-repeat; |
| ... | ... | @@ -14,3 +15,4 @@ div.issue_tracker.nested label.r_on.<%= tracker %> { |
| 14 | 15 | background: transparent url(/assets/<%= tracker %>_goto.png) 6px 5px no-repeat; |
| 15 | 16 | } |
| 16 | 17 | <% end %> |
| 18 | + | ... | ... |
app/assets/stylesheets/notification_service_icons.css.erb
0 → 100644
| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | + /* Notification Service inactive, select, create and goto icons */ | |
| 2 | +<% notification_services = NotificationService.subclasses.map{|t| t.label } << 'none' %> | |
| 3 | + | |
| 4 | +<% notification_services.each do |notification_service| %> | |
| 5 | +div.notification_service.nested label.<%= notification_service %> { | |
| 6 | + background: url(/assets/<%= notification_service %>_inactive.png) no-repeat; | |
| 7 | +} | |
| 8 | +div.notification_service.nested label.r_on.<%= notification_service %> { | |
| 9 | + background: url(/assets/<%= notification_service %>_create.png) no-repeat; | |
| 10 | +} | |
| 11 | +#action-bar a.<%= notification_service %>_create { | |
| 12 | + background: transparent url(/assets/<%= notification_service %>_create.png) 6px 5px no-repeat; | |
| 13 | +} | |
| 14 | +#action-bar a.<%= notification_service %>_goto { | |
| 15 | + background: transparent url(/assets/<%= notification_service %>_goto.png) 6px 5px no-repeat; | |
| 16 | +} | |
| 17 | +<% end %> | |
| 18 | + | ... | ... |
app/controllers/apps_controller.rb
| ... | ... | @@ -29,12 +29,14 @@ class AppsController < InheritedResources::Base |
| 29 | 29 | def create |
| 30 | 30 | @app = App.new(params[:app]) |
| 31 | 31 | initialize_subclassed_issue_tracker |
| 32 | + initialize_subclassed_notification_service | |
| 32 | 33 | create! |
| 33 | 34 | end |
| 34 | 35 | |
| 35 | 36 | def update |
| 36 | 37 | @app = resource |
| 37 | 38 | initialize_subclassed_issue_tracker |
| 39 | + initialize_subclassed_notification_service | |
| 38 | 40 | update! |
| 39 | 41 | end |
| 40 | 42 | |
| ... | ... | @@ -70,6 +72,7 @@ class AppsController < InheritedResources::Base |
| 70 | 72 | end |
| 71 | 73 | |
| 72 | 74 | def initialize_subclassed_issue_tracker |
| 75 | + # set the app's issue tracker | |
| 73 | 76 | if params[:app][:issue_tracker_attributes] && tracker_type = params[:app][:issue_tracker_attributes][:type] |
| 74 | 77 | if IssueTracker.subclasses.map(&:name).concat(["IssueTracker"]).include?(tracker_type) |
| 75 | 78 | @app.issue_tracker = tracker_type.constantize.new(params[:app][:issue_tracker_attributes]) |
| ... | ... | @@ -77,6 +80,15 @@ class AppsController < InheritedResources::Base |
| 77 | 80 | end |
| 78 | 81 | end |
| 79 | 82 | |
| 83 | + def initialize_subclassed_notification_service | |
| 84 | + # set the app's notification service | |
| 85 | + if params[:app][:notification_service_attributes] && notification_type = params[:app][:notification_service_attributes][:type] | |
| 86 | + if NotificationService.subclasses.map(&:name).concat(["NotificationService"]).include?(notification_type) | |
| 87 | + @app.notification_service = notification_type.constantize.new(params[:app][:notification_service_attributes]) | |
| 88 | + end | |
| 89 | + end | |
| 90 | + end | |
| 91 | + | |
| 80 | 92 | def begin_of_association_chain |
| 81 | 93 | # Filter the @apps collection to apps watched by the current user, unless user is an admin. |
| 82 | 94 | # If user is an admin, then no filter is applied, and all apps are shown. |
| ... | ... | @@ -90,6 +102,7 @@ class AppsController < InheritedResources::Base |
| 90 | 102 | def plug_params app |
| 91 | 103 | app.watchers.build if app.watchers.none? |
| 92 | 104 | app.issue_tracker = IssueTracker.new unless app.issue_tracker_configured? |
| 105 | + app.notification_service = NotificationService.new unless app.notification_service_configured? | |
| 93 | 106 | app.copy_attributes_from(params[:copy_attributes_from]) if params[:copy_attributes_from] |
| 94 | 107 | end |
| 95 | 108 | ... | ... |
app/helpers/apps_helper.rb
| ... | ... | @@ -16,6 +16,11 @@ module AppsHelper |
| 16 | 16 | @any_github_repos |
| 17 | 17 | end |
| 18 | 18 | |
| 19 | + def any_notification_services? | |
| 20 | + detect_any_apps_with_attributes unless @any_notification_services | |
| 21 | + @any_notification_services | |
| 22 | + end | |
| 23 | + | |
| 19 | 24 | def any_issue_trackers? |
| 20 | 25 | detect_any_apps_with_attributes unless @any_issue_trackers |
| 21 | 26 | @any_issue_trackers |
| ... | ... | @@ -29,11 +34,12 @@ module AppsHelper |
| 29 | 34 | private |
| 30 | 35 | |
| 31 | 36 | def detect_any_apps_with_attributes |
| 32 | - @any_github_repos = @any_issue_trackers = @any_deploys = false | |
| 37 | + @any_github_repos = @any_issue_trackers = @any_deploys = @any_notification_services = false | |
| 33 | 38 | @apps.each do |app| |
| 34 | 39 | @any_github_repos ||= app.github_repo? |
| 35 | 40 | @any_issue_trackers ||= app.issue_tracker_configured? |
| 36 | 41 | @any_deploys ||= !!app.last_deploy_at |
| 42 | + @any_notification_services ||= app.notification_service_configured? | |
| 37 | 43 | end |
| 38 | 44 | end |
| 39 | 45 | end | ... | ... |
app/models/app.rb
| ... | ... | @@ -17,6 +17,8 @@ class App |
| 17 | 17 | embeds_many :watchers |
| 18 | 18 | embeds_many :deploys |
| 19 | 19 | embeds_one :issue_tracker |
| 20 | + embeds_one :notification_service | |
| 21 | + | |
| 20 | 22 | has_many :problems, :inverse_of => :app, :dependent => :destroy |
| 21 | 23 | |
| 22 | 24 | before_validation :generate_api_key, :on => :create |
| ... | ... | @@ -33,7 +35,8 @@ class App |
| 33 | 35 | :reject_if => proc { |attrs| attrs[:user_id].blank? && attrs[:email].blank? } |
| 34 | 36 | accepts_nested_attributes_for :issue_tracker, :allow_destroy => true, |
| 35 | 37 | :reject_if => proc { |attrs| !IssueTracker.subclasses.map(&:to_s).include?(attrs[:type].to_s) } |
| 36 | - | |
| 38 | + accepts_nested_attributes_for :notification_service, :allow_destroy => true, | |
| 39 | + :reject_if => proc { |attrs| !NotificationService.subclasses.map(&:to_s).include?(attrs[:type].to_s) } | |
| 37 | 40 | |
| 38 | 41 | # Processes a new error report. |
| 39 | 42 | # |
| ... | ... | @@ -121,6 +124,11 @@ class App |
| 121 | 124 | !!(issue_tracker && issue_tracker.class < IssueTracker && issue_tracker.project_id.present?) |
| 122 | 125 | end |
| 123 | 126 | |
| 127 | + def notification_service_configured? | |
| 128 | + !!(notification_service && notification_service.class < NotificationService && notification_service.api_token.present?) | |
| 129 | + end | |
| 130 | + | |
| 131 | + | |
| 124 | 132 | def notification_recipients |
| 125 | 133 | if notify_all_users |
| 126 | 134 | (User.all.map(&:email).reject(&:blank?) + watchers.map(&:address)).uniq |
| ... | ... | @@ -137,7 +145,7 @@ class App |
| 137 | 145 | self.send("#{k}=", copy_app.send(k)) |
| 138 | 146 | end |
| 139 | 147 | # Clone the embedded objects that can be changed via apps/edit (ignore errs & deploys, etc.) |
| 140 | - %w(watchers issue_tracker).each do |relation| | |
| 148 | + %w(watchers issue_tracker notification_service).each do |relation| | |
| 141 | 149 | if obj = copy_app.send(relation) |
| 142 | 150 | self.send("#{relation}=", obj.is_a?(Array) ? obj.map(&:clone) : obj.clone) |
| 143 | 151 | end | ... | ... |
app/models/issue_tracker.rb
app/models/notice_observer.rb
| ... | ... | @@ -4,6 +4,11 @@ class NoticeObserver < Mongoid::Observer |
| 4 | 4 | def after_create notice |
| 5 | 5 | return unless should_notify? notice |
| 6 | 6 | |
| 7 | + # if the app has a notficiation service, fire it off | |
| 8 | + unless notice.app.notification_service.nil? | |
| 9 | + notice.app.notification_service.create_notification(notice.problem) | |
| 10 | + end | |
| 11 | + | |
| 7 | 12 | Mailer.err_notification(notice).deliver |
| 8 | 13 | end |
| 9 | 14 | |
| ... | ... | @@ -15,5 +20,4 @@ class NoticeObserver < Mongoid::Observer |
| 15 | 20 | (Errbit::Config.per_app_email_at_notices && app.email_at_notices || Errbit::Config.email_at_notices).include?(notice.problem.notices_count) && |
| 16 | 21 | app.notification_recipients.any? |
| 17 | 22 | end |
| 18 | - | |
| 19 | 23 | end | ... | ... |
| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | +class NotificationService | |
| 2 | + include Mongoid::Document | |
| 3 | + | |
| 4 | + field :room_id, :type => String | |
| 5 | + field :api_token, :type => String | |
| 6 | + field :subdomain, :type => String | |
| 7 | + | |
| 8 | + embedded_in :app, :inverse_of => :notification_service | |
| 9 | + | |
| 10 | + validate :check_params | |
| 11 | + | |
| 12 | + # Subclasses are responsible for overwriting this method. | |
| 13 | + def check_params; true; end | |
| 14 | + | |
| 15 | + def notification_description(problem) | |
| 16 | + "[#{ problem.environment }][#{ problem.where }] #{problem.message.to_s.truncate(100)}" | |
| 17 | + end | |
| 18 | + | |
| 19 | + # Allows us to set the issue tracker class from a single form. | |
| 20 | + def type; self._type; end | |
| 21 | + def type=(t); self._type=t; end | |
| 22 | + | |
| 23 | + # Retrieve tracker label from either class or instance. | |
| 24 | + Label = '' | |
| 25 | + def self.label; self::Label; end | |
| 26 | + def label; self.class.label; end | |
| 27 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | +class NotificationService::CampfireService < NotificationService | |
| 2 | + Label = "campfire" | |
| 3 | + Fields = [ | |
| 4 | + [:subdomain, { | |
| 5 | + :placeholder => "Campfire Subdomain" | |
| 6 | + }], | |
| 7 | + [:api_token, { | |
| 8 | + :placeholder => "API Token" | |
| 9 | + }], | |
| 10 | + [:room_id, { | |
| 11 | + :placeholder => "Room ID", | |
| 12 | + :label => "Room ID" | |
| 13 | + }], | |
| 14 | + ] | |
| 15 | + | |
| 16 | + def check_params | |
| 17 | + if Fields.detect {|f| self[f[0]].blank? } | |
| 18 | + errors.add :base, 'You must specify your Campfire Subdomain, API token and Room ID' | |
| 19 | + end | |
| 20 | + end | |
| 21 | + | |
| 22 | + def create_notification(problem) | |
| 23 | + # build the campfire client | |
| 24 | + campy = Campy::Room.new(:account => subdomain, :token => api_token, :room_id => room_id) | |
| 25 | + | |
| 26 | + # post the issue to the campfire room | |
| 27 | + campy.speak "[errbit] http://#{Errbit::Config.host}/apps/#{problem.app.id.to_s} #{notification_description problem}" | |
| 28 | + end | |
| 29 | +end | |
| 0 | 30 | \ No newline at end of file | ... | ... |
app/views/apps/_fields.html.haml
| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | +%fieldset | |
| 2 | + %legend Notification Service | |
| 3 | + = f.fields_for :notification_service do |w| | |
| 4 | + %div.notification_service.nested | |
| 5 | + %div.choose | |
| 6 | + = label_tag :type_none, :for => label_for_attr(w, 'type_notificationservice'), :class => "label_radio none" do | |
| 7 | + = w.radio_button :type, "NotificationService", 'data-section' => 'none' | |
| 8 | + (None) | |
| 9 | + - NotificationService.subclasses.each do |notification_service| | |
| 10 | + = label_tag "type_#{notification_service.label}:", :for => label_for_attr(w, "type_#{notification_service.name.downcase.gsub(':','')}"), :class => "label_radio #{notification_service.label}" do | |
| 11 | + = w.radio_button :type, notification_service.name, 'data-section' => notification_service.label | |
| 12 | + = notification_service.name[/::(.*)Service/,1].titleize | |
| 13 | + | |
| 14 | + %div.notification_params.none{:class => (w.object && !(w.object.class < NotificationService)) ? 'chosen' : nil} | |
| 15 | + - NotificationService.subclasses.each do |notification_service| | |
| 16 | + %div.notification_params{:class => (w.object.is_a?(notification_service) ? 'chosen ' : '') << notification_service.label} | |
| 17 | + - notification_service::Fields.each do |field, field_info| | |
| 18 | + = w.label field, field_info[:label] || field.to_s.titleize | |
| 19 | + - field_type = field == :password ? :password_field : :text_field | |
| 20 | + = w.send field_type, field, :placeholder => field_info[:placeholder], :value => w.object.send(field) | |
| 21 | + | |
| 22 | + .image_preloader | |
| 23 | + - (NotificationService.subclasses.map{|t| t.label } << 'none').each do |notification_service| | |
| 24 | + = image_tag "#{notification_service}_inactive.png" | |
| 25 | + = image_tag "#{notification_service}_create.png" | ... | ... |
app/views/apps/index.html.haml
| ... | ... | @@ -8,6 +8,8 @@ |
| 8 | 8 | %th Name |
| 9 | 9 | - if any_github_repos? |
| 10 | 10 | %th GitHub Repo |
| 11 | + - if any_notification_services? | |
| 12 | + %th Notification Service | |
| 11 | 13 | - if any_issue_trackers? |
| 12 | 14 | %th Tracker |
| 13 | 15 | - if any_deploys? |
| ... | ... | @@ -21,6 +23,10 @@ |
| 21 | 23 | %td.github_repo |
| 22 | 24 | - if app.github_repo? |
| 23 | 25 | = link_to(app.github_repo, app.github_url, :target => '_blank') |
| 26 | + - if any_notification_services? | |
| 27 | + %td.notification_service | |
| 28 | + - if app.notification_service_configured? | |
| 29 | + = image_tag("#{app.notification_service.label}_goto.png") | |
| 24 | 30 | - if any_issue_trackers? |
| 25 | 31 | %td.issue_tracker |
| 26 | 32 | - if app.issue_tracker_configured? | ... | ... |
config/environments/production.rb
spec/fabricators/issue_tracker_fabricator.rb
| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | +Fabricator :notification_service do | |
| 2 | + app! | |
| 3 | + room_id { sequence :word } | |
| 4 | + api_token { sequence :word } | |
| 5 | + subdomain { sequence :word } | |
| 6 | +end | |
| 7 | + | |
| 8 | +%w(campfire).each do |t| | |
| 9 | + Fabricator "#{t}_notification_service".to_sym, :from => :notification_service, :class_name => "NotificationService::#{t.camelcase}Service" | |
| 10 | +end | ... | ... |
spec/models/notice_observer_spec.rb
| ... | ... | @@ -25,7 +25,6 @@ describe NoticeObserver do |
| 25 | 25 | end |
| 26 | 26 | |
| 27 | 27 | describe "email notifications for a resolved issue" do |
| 28 | - | |
| 29 | 28 | before do |
| 30 | 29 | Errbit::Config.per_app_email_at_notices = true |
| 31 | 30 | @app = Fabricate(:app_with_watcher, :email_at_notices => [1]) |
| ... | ... | @@ -43,4 +42,28 @@ describe NoticeObserver do |
| 43 | 42 | Fabricate(:notice, :err => @err) |
| 44 | 43 | end |
| 45 | 44 | end |
| 45 | + | |
| 46 | + describe "should send a notification if a notification service is configured" do | |
| 47 | + let(:app) { app = Fabricate(:app, :email_at_notices => [1], :notification_service => Fabricate(:campfire_notification_service))} | |
| 48 | + let(:err) { Fabricate(:err, :problem => Fabricate(:problem, :app => app, :notices_count => 100)) } | |
| 49 | + | |
| 50 | + before do | |
| 51 | + Errbit::Config.per_app_email_at_notices = true | |
| 52 | + end | |
| 53 | + | |
| 54 | + after do | |
| 55 | + Errbit::Config.per_app_email_at_notices = false | |
| 56 | + end | |
| 57 | + | |
| 58 | + it "should create a campfire notification" do | |
| 59 | + err.problem.stub(:notices_count) { 1 } | |
| 60 | + app.notification_service.stub!(:create_notification).and_return(true) | |
| 61 | + app.stub!(:notification_recipients => %w('ryan@system88.com')) | |
| 62 | + app.notification_service.should_receive(:create_notification) | |
| 63 | + | |
| 64 | + Notice.create!(:err => err, :message => 'FooError: Too Much Bar', :server_environment => {'environment-name' => 'production'}, | |
| 65 | + :backtrace => [{ :error => 'Le Broken' }], :notifier => { 'name' => 'Notifier', 'version' => '1', 'url' => 'http://toad.com' }) | |
| 66 | + end | |
| 67 | + end | |
| 68 | + | |
| 46 | 69 | end | ... | ... |
spec/models/notification_service/campfire_service_spec.rb
0 → 100644
| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | +require 'spec_helper' | |
| 2 | + | |
| 3 | +describe NotificationService::CampfireService do | |
| 4 | + it "it should send a notification to campfire" do | |
| 5 | + # setup | |
| 6 | + notice = Fabricate :notice | |
| 7 | + notification_service = Fabricate :campfire_notification_service, :app => notice.app | |
| 8 | + problem = notice.problem | |
| 9 | + | |
| 10 | + #campy stubbing | |
| 11 | + campy = mock('CampfireService') | |
| 12 | + Campy::Room.stub(:new).and_return(campy) | |
| 13 | + campy.stub(:speak) { true } | |
| 14 | + | |
| 15 | + #assert | |
| 16 | + campy.should_receive(:speak) | |
| 17 | + | |
| 18 | + notification_service.create_notification(problem) | |
| 19 | + end | |
| 20 | +end | |
| 21 | + | ... | ... |