require 'spec_helper' require 'flapjack/gateways/jabber' describe Flapjack::Gateways::Jabber, :logger => true do let(:config) { {'queue' => 'jabber_notifications', 'server' => 'example.com', 'port' => '5222', 'jabberid' => 'flapjack@example.com', 'password' => 'password', 'alias' => 'flapjack', 'rooms' => ['flapjacktest@conference.example.com'] } } let(:stanza) { double('stanza') } it "hooks up event handlers to the appropriate methods" do Socket.should_receive(:gethostname).and_return('thismachine') Flapjack::RedisPool.should_receive(:new) fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger) EventMachine::Synchrony.should_receive(:next_tick).exactly(4).times.and_yield fj.should_receive(:register_handler).with(:ready).and_yield(stanza) fj.should_receive(:on_ready).with(stanza) fj.should_receive(:register_handler).with(:message, :groupchat?, :body => /^flapjack:\s+/).and_yield(stanza) fj.should_receive(:on_groupchat).with(stanza) fj.should_receive(:register_handler).with(:message, :chat?).and_yield(stanza) fj.should_receive(:on_chat).with(stanza) fj.should_receive(:register_handler).with(:disconnected).and_yield(stanza) fj.should_receive(:on_disconnect).with(stanza).and_return(true) fj.setup end it "joins a chat room after connecting" do Flapjack::RedisPool.should_receive(:new) fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger) fj.should_receive(:connected?).and_return(true) EventMachine::Synchrony.should_receive(:next_tick).and_yield fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Presence)) fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message)) fj.on_ready(stanza) end it "receives an acknowledgement message" do stanza.should_receive(:body).and_return('flapjack: ACKID 876 fixing now duration: 90m') from = double('from') from.should_receive(:stripped).and_return('sender') stanza.should_receive(:from).and_return(from) redis = double('redis') redis.should_receive(:hget).with('unacknowledged_failures', '876'). and_return('main-example.com:ping') entity_check = double(Flapjack::Data::EntityCheck) entity_check.should_receive(:in_unscheduled_maintenance?) Flapjack::Data::Event.should_receive(:create_acknowledgement). with('main-example.com', 'ping', :summary => 'fixing now', :acknowledgement_id => '876', :duration => (90 * 60), :redis => redis) Flapjack::Data::EntityCheck.should_receive(:for_event_id). with('main-example.com:ping', :redis => redis). and_return(entity_check) Flapjack::RedisPool.should_receive(:new).and_return(redis) fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger) EventMachine::Synchrony.should_receive(:next_tick).and_yield fj.should_receive(:connected?).and_return(true) fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message)) fj.on_groupchat(stanza) end it "strips XML tags from the received message" do stanza.should_receive(:body). and_return('flapjack: tell me about ' + 'example.org') from = double('from') from.should_receive(:stripped).and_return('sender') stanza.should_receive(:from).and_return(from) redis = double('redis') entity = double(Flapjack::Data::Entity) entity.should_receive(:check_list).and_return(['ping']) Flapjack::Data::Entity.should_receive(:find_by_name).with('example.org', :redis => redis).and_return(entity) entity_check = double(Flapjack::Data::EntityCheck) entity_check.should_receive(:current_maintenance).with(:scheduled => true).and_return(nil) entity_check.should_receive(:current_maintenance).with(:unscheduled => true).and_return(nil) Flapjack::Data::EntityCheck.should_receive(:for_entity).with(entity, 'ping', :redis => redis).and_return(entity_check) Flapjack::RedisPool.should_receive(:new).and_return(redis) fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger) EventMachine::Synchrony.should_receive(:next_tick).and_yield fj.should_receive(:connected?).and_return(true) fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message)) fj.on_groupchat(stanza) end it "handles a message with a newline in it" do stanza.should_receive(:body). and_return("flapjack: tell me about \nexample.com") from = double('from') from.should_receive(:stripped).and_return('sender') stanza.should_receive(:from).and_return(from) redis = double('redis') entity = double(Flapjack::Data::Entity) entity.should_receive(:check_list).and_return(['ping']) Flapjack::Data::Entity.should_receive(:find_by_name).with('example.com', :redis => redis).and_return(entity) entity_check = double(Flapjack::Data::EntityCheck) entity_check.should_receive(:current_maintenance).with(:scheduled => true).and_return(nil) entity_check.should_receive(:current_maintenance).with(:unscheduled => true).and_return(nil) Flapjack::Data::EntityCheck.should_receive(:for_entity).with(entity, 'ping', :redis => redis).and_return(entity_check) Flapjack::RedisPool.should_receive(:new).and_return(redis) fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger) EventMachine::Synchrony.should_receive(:next_tick).and_yield fj.should_receive(:connected?).and_return(true) fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message)) fj.on_groupchat(stanza) end it "receives a message it doesn't understand" do stanza.should_receive(:body).once.and_return('flapjack: hello!') from = double('from') from.should_receive(:stripped).and_return('sender') stanza.should_receive(:from).and_return(from) Flapjack::RedisPool.should_receive(:new) fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger) EventMachine::Synchrony.should_receive(:next_tick).and_yield fj.should_receive(:connected?).and_return(true) fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message)) fj.on_groupchat(stanza) end it "reconnects when disconnected (if not quitting)" do Flapjack::RedisPool.should_receive(:new) fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger) attempts = 0 EventMachine::Synchrony.should_receive(:sleep).with(5).exactly(1).times EventMachine::Synchrony.should_receive(:sleep).with(2).exactly(3).times fj.should_receive(:connect).exactly(4).times.and_return { attempts +=1 raise StandardError.new unless attempts > 3 } ret = fj.on_disconnect(stanza) ret.should be_true end it "prompts the blocking redis connection to quit" do shutdown_redis = double('shutdown_redis') shutdown_redis.should_receive(:rpush).with('jabber_notifications', %q{{"notification_type":"shutdown"}}) EM::Hiredis.should_receive(:connect).and_return(shutdown_redis) redis = double('redis') Flapjack::RedisPool.should_receive(:new).and_return(redis) fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger) fj.stop end it "runs a blocking loop listening for notifications" do timer = double('timer') timer.should_receive(:cancel) EM::Synchrony.should_receive(:add_periodic_timer).with(1).and_return(timer) redis = double('redis') Flapjack::RedisPool.should_receive(:new).and_return(redis) fj = Flapjack::Gateways::Jabber.new(:config => config, :logger => @logger) fj.should_receive(:register_handler).exactly(4).times fj.should_receive(:connect) fj.should_receive(:connected?).exactly(3).times.and_return(true) blpop_count = 0 event_json = '{"notification_type":"problem","event_id":"main-example.com:ping",' + '"state":"critical","summary":"!!!","duration":43,"state_duration":76}' redis.should_receive(:blpop).twice { blpop_count += 1 if blpop_count == 1 ["jabber_notifications", event_json] else fj.instance_variable_set('@should_quit', true) ["jabber_notifications", %q{{"notification_type":"shutdown"}}] end } EventMachine::Synchrony.should_receive(:next_tick).twice.and_yield fj.should_receive(:write).with(an_instance_of(Blather::Stanza::Message)) fj.should_receive(:close) fj.start @logger.errors.should be_empty end end